

# Lock:tuple
<a name="apg-waits.locktuple"></a>

O evento `Lock:tuple` ocorre quando um processo de backend está aguardando para adquirir um bloqueio em uma tupla.

**Topics**
+ [Versões compatíveis do mecanismo](#apg-waits.locktuple.context.supported)
+ [Contexto](#apg-waits.locktuple.context)
+ [Possíveis causas do maior número de esperas](#apg-waits.locktuple.causes)
+ [Ações](#apg-waits.locktuple.actions)

## Versões compatíveis do mecanismo
<a name="apg-waits.locktuple.context.supported"></a>

Essas informações de eventos de espera têm suporte para todas as versões do Aurora PostgreSQL.

## Contexto
<a name="apg-waits.locktuple.context"></a>

O evento `Lock:tuple` indica que um backend está aguardando para adquirir um bloqueio em uma tupla enquanto outro backend mantém um bloqueio conflitante na mesma tupla. A tabela a seguir ilustra um cenário em que as sessões geram o evento `Lock:tuple`.


|  Tempo  |  Sessão 1  |  Sessão 2  |  Sessão 3  | 
| --- | --- | --- | --- | 
|  t1  |  Inicia uma transação.  |    |    | 
|  t2  |  Atualiza a linha 1.  |    |    | 
|  t3  |    |  Atualiza a linha 1. A sessão adquire um bloqueio exclusivo na tupla e aguarda a sessão 1 liberar esse bloqueio via confirmação ou reversão.  |    | 
|  t4  |    |    |  Atualiza a linha 1. A sessão aguarda a sessão 2 liberar o bloqueio exclusivo na tupla.  | 

Outra alternativa é simular esse evento de espera utilizando a ferramenta de benchmarking `pgbench`. Configure um número elevado de sessões simultâneas para atualizar a mesma linha em uma tabela com um arquivo SQL personalizado.

Para saber mais sobre modos de bloqueio conflitantes, consulte o tópico sobre [Bloqueio explícito](https://www.postgresql.org/docs/current/explicit-locking.html), na documentação do PostgreSQL. Para saber mais sobre `pgbench`, consulte [pgbench](https://www.postgresql.org/docs/current/pgbench.html) na documentação do PostgreSQL.

## Possíveis causas do maior número de esperas
<a name="apg-waits.locktuple.causes"></a>

Quando esse evento aparece mais que o normal, possivelmente indicando um problema de performance, as causas típicas incluem:
+ Um número elevado de sessões simultâneas está tentando adquirir um bloqueio conflitante para a mesma tupla executando instruções `UPDATE` ou `DELETE`.
+ Sessões altamente simultâneas estão executando uma instrução `SELECT` utilizando os modos de bloqueio `FOR UPDATE` ou `FOR NO KEY UPDATE`.
+ Diversos fatores fazem com que grupos de aplicações ou conexões abram mais sessões para executar as mesmas operações. À medida que novas sessões estão tentando modificar as mesmas linhas, a carga de banco de dados pode atingir picos e `Lock:tuple` pode surgir.

Para obter mais informações, consulte o tópico sobre [Bloqueios em nível de linha](https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS), na documentação do PostgreSQL.

## Ações
<a name="apg-waits.locktuple.actions"></a>

Recomenda-se ações distintas, dependendo dos motivos do evento de espera.

**Topics**
+ [Investigar a lógica da sua aplicação](#apg-waits.locktuple.actions.problem)
+ [Localizar a sessão bloqueadora](#apg-waits.locktuple.actions.find-blocker)
+ [Reduzir a simultaneidade quando ela estiver elevada](#apg-waits.locktuple.actions.concurrency)
+ [Solucionar problemas de gargalos](#apg-waits.locktuple.actions.bottlenecks)

### Investigar a lógica da sua aplicação
<a name="apg-waits.locktuple.actions.problem"></a>

Descubra se uma sessão bloqueadora está no estado `idle in transaction` por muito tempo. Em caso positivo, considere encerrar a sessão bloqueadora como uma solução de curto prazo. Também é possível utilizar a função `pg_terminate_backend`. Para obter mais informações sobre essa função, consulte [Funções de sinalização de servidor](https://www.postgresql.org/docs/13/functions-admin.html#FUNCTIONS-ADMIN-SIGNAL), na documentação do PostgreSQL.

Para uma solução de longo prazo, faça o seguinte:
+ Ajuste a lógica da aplicação.
+ Use o parâmetro `idle_in_transaction_session_timeout`. Esse parâmetro encerra qualquer sessão com uma transação aberta que tenha ficado ociosa por um tempo maior que o especificado. Para obter mais informações, consulte o tópico sobre [Padrões de conexão de clientes](https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-IDLE-IN-TRANSACTION-SESSION-TIMEOUT), na documentação do PostgreSQL.
+ Use a confirmação automática o máximo possível. Para obter mais informações, consulte [SET AUTOCOMMIT](https://www.postgresql.org/docs/current/ecpg-sql-set-autocommit.html), na documentação do PostgreSQL.

### Localizar a sessão bloqueadora
<a name="apg-waits.locktuple.actions.find-blocker"></a>

Enquanto o evento de espera `Lock:tuple` está ocorrendo, identifique a sessão bloqueadora e a sessão bloqueada descobrindo quais bloqueios dependem um do outro. Para obter mais informações, consulte o tópico sobre [Informações de dependências de bloqueios](https://wiki.postgresql.org/wiki/Lock_dependency_information), na wiki do PostgreSQL. Para analisar eventos `Lock:tuple` passados, utilize a função do Aurora `aurora_stat_backend_waits`. 

O exemplo a seguir consulta todas as sessões, filtrando em `tuple` e ordenando por `wait_time`.

```
--AURORA_STAT_BACKEND_WAITS
      SELECT a.pid, 
             a.usename, 
             a.app_name, 
             a.current_query,
             a.current_wait_type, 
             a.current_wait_event, 
             a.current_state, 
             wt.type_name AS wait_type, 
             we.event_name AS wait_event, 
             a.waits, 
             a.wait_time
        FROM (SELECT pid, 
                     usename, 
                     left(application_name,16) AS app_name,
                     coalesce(wait_event_type,'CPU') AS current_wait_type,
                     coalesce(wait_event,'CPU') AS current_wait_event, 
                     state AS current_state,
                     left(query,80) as current_query,
                     (aurora_stat_backend_waits(pid)).* 
                FROM pg_stat_activity 
               WHERE pid <> pg_backend_pid()
                 AND usename<>'rdsadmin') a
NATURAL JOIN aurora_stat_wait_type() wt 
NATURAL JOIN aurora_stat_wait_event() we
WHERE we.event_name = 'tuple'
    ORDER BY a.wait_time;

  pid  | usename | app_name |                 current_query                  | current_wait_type | current_wait_event | current_state | wait_type | wait_event | waits | wait_time
-------+---------+----------+------------------------------------------------+-------------------+--------------------+---------------+-----------+------------+-------+-----------
 32136 | sys     | psql     | /*session3*/ update tab set col=1 where col=1; | Lock              | tuple              | active        | Lock      | tuple      |     1 |   1000018
 11999 | sys     | psql     | /*session4*/ update tab set col=1 where col=1; | Lock              | tuple              | active        | Lock      | tuple      |     1 |   1000024
```

### Reduzir a simultaneidade quando ela estiver elevada
<a name="apg-waits.locktuple.actions.concurrency"></a>

O evento `Lock:tuple` pode ocorrer constantemente, especialmente em um tempo de workload ocupado. Nessa situação, considere reduzir a simultaneidade elevada para linhas muito ocupadas. Várias vezes, apenas algumas linhas controlam uma fila ou a lógica booleana, o que torna essas linhas muito ocupadas.

Você pode reduzir a simultaneidade utilizando diferentes abordagens com base no seu requisito de negócios, na lógica da aplicação e no tipo de workload. Por exemplo, você pode fazer o seguinte:
+ Reformule sua tabela e a lógica de dados para reduzir a simultaneidade elevada.
+ Altere a lógica da aplicação para reduzir a simultaneidade elevada no nível da linha.
+ Aproveite e reformule consultas com bloqueios em nível de linha.
+ Use a cláusula `NOWAIT` com operações de novas tentativas.
+ Considere utilizar o controle de simultaneidade lógico otimista e bloqueio híbrido.
+ Considere modificar o nível de isolamento do banco de dados.

### Solucionar problemas de gargalos
<a name="apg-waits.locktuple.actions.bottlenecks"></a>

O `Lock:tuple` pode ocorrer com gargalos, como falta de CPU ou uso máximo da largura de banda do Amazon EBS. Para diminuir gargalos, considere as seguintes abordagens:
+ Aumente a escala do seu tipo de classe de instância na vertical.
+ Otimize consultas que consomem muitos recursos.
+ Altere a lógica da aplicação.
+ Arquive dados acessados raramente.