

# Lock:advisory
<a name="apg-waits.lockadvisory"></a>

O evento `Lock:advisory` ocorre quando uma aplicação PostgreSQL utiliza um bloqueio para coordenar as atividades em várias sessões.

**Topics**
+ [Versões de mecanismos relevantes](#apg-waits.lockadvisory.context.supported)
+ [Contexto](#apg-waits.lockadvisory.context)
+ [Causas](#apg-waits.lockadvisory.causes)
+ [Ações](#apg-waits.lockadvisory.actions)

## Versões de mecanismos relevantes
<a name="apg-waits.lockadvisory.context.supported"></a>

As informações sobre eventos de espera são relevantes para o Aurora PostgreSQL versão 9.6 e versões superiores.

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

Bloqueios consultivos do PostgreSQL são bloqueios cooperativos em nível de aplicação, feitos explicitamente e desfeitos pelo código da aplicação do usuário. Uma aplicação pode utilizar bloqueios consultivos do PostgreSQL para coordenar atividades em várias sessões. Ao contrário de bloqueios regulares, ou em nível de objeto ou linha, a aplicação tem controle total ao longo da vida útil do bloqueio. Para obter mais informações, consulte o tópico sobre [Bloqueios consultivos](https://www.postgresql.org/docs/12/explicit-locking.html#ADVISORY-LOCKS) na documentação do PostgreSQL.

Bloqueios consultivos podem ser liberados antes que uma transação termine ou podem ser mantidos por uma sessão em todas as transações. Isso não é válido para bloqueios implícitos aplicados pelo sistema, como um bloqueio exclusivo de acesso em uma tabela adquirida por uma instrução `CREATE INDEX`.

Para obter uma descrição das funções utilizadas para adquirir (bloquear) e liberar (desbloquear) bloqueios consultivos, consulte o tópico sobre [Funções de bloqueios consultivos](https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS), na documentação do PostgreSQL.

Bloqueios consultivos são implementados sobre o sistema de bloqueio regular do PostgreSQL e ficam visíveis na visualização do sistema `pg_locks`.

## Causas
<a name="apg-waits.lockadvisory.causes"></a>

Esse tipo de bloqueio é controlado exclusivamente por uma aplicação que o utiliza explicitamente. Bloqueios consultivos que são adquiridos para cada linha como parte de uma consulta podem causar um aumento nos bloqueios ou um acúmulo a longo prazo.

Esses efeitos acontecem quando a consulta é executada de uma maneira que adquire bloqueios em mais linhas do que as retornadas pela consulta. A aplicação deve eventualmente liberar todos os bloqueios, mas, se eles forem adquiridos em linhas que não são retornadas, a aplicação não poderá localizar todos os bloqueios.

O exemplo a seguir foi extraído do tópico [Bloqueios consultivos](https://www.postgresql.org/docs/12/explicit-locking.html#ADVISORY-LOCKS) na documentação do PostgreSQL.

```
SELECT pg_advisory_lock(id) FROM foo WHERE id > 12345 LIMIT 100;
```

Nesse exemplo, a cláusula `LIMIT` apenas pode interromper a saída da consulta depois que as linhas já foram selecionadas internamente e seus valores de ID estão bloqueados. Isso pode acontecer repentinamente quando um volume de dados crescente faz com que o planejador escolha um plano de execução diferente que não foi testado durante o desenvolvimento. O acúmulo nesse caso acontece porque a aplicação chama explicitamente `pg_advisory_unlock` para cada valor de ID bloqueado. No entanto, nesse caso, não é possível encontrar o conjunto de bloqueios adquiridos em linhas que não foram retornadas. Como os bloqueios são adquiridos em nível de sessão, eles não são liberados automaticamente no final da transação.

Outra possível causa para picos em tentativas de bloqueio bloqueadas são conflitos não intencionais. Nesses conflitos, partes não relacionadas da aplicação compartilham o mesmo espaço de ID de bloqueio por engano.

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

Revise o uso da aplicação de bloqueios consultivos e detalhe onde e quando no fluxo de aplicação cada tipo de bloqueio consultivo é adquirido e liberado.

Determine se uma sessão está adquirindo muitos bloqueios ou se uma sessão de longa execução não está liberando bloqueios cedo o suficiente, resultando em um acúmulo lento de bloqueios. Você pode corrigir um acúmulo lento de bloqueios em nível de sessão encerrando a sessão com `pg_terminate_backend(pid)`. 

Um cliente que aguarda um bloqueio de consultoria aparece em `pg_stat_activity` com `wait_event_type=Lock` e `wait_event=advisory`. É possível obter valores de bloqueio específicos consultando a visualização do sistema `pg_locks` em busca do mesmo `pid`, procurando `locktype=advisory` e `granted=f`.

Em seguida, identifique a sessão de bloqueio consultando `pg_locks` em busca do mesmo bloqueio consultivo que possui `granted=t`, conforme mostrado no exemplo a seguir.

```
SELECT blocked_locks.pid AS blocked_pid,
         blocking_locks.pid AS blocking_pid,
         blocked_activity.usename AS blocked_user,
         blocking_activity.usename AS blocking_user,
         now() - blocked_activity.xact_start AS blocked_transaction_duration,
         now() - blocking_activity.xact_start AS blocking_transaction_duration,
         concat(blocked_activity.wait_event_type,':',blocked_activity.wait_event) AS blocked_wait_event,
         concat(blocking_activity.wait_event_type,':',blocking_activity.wait_event) AS blocking_wait_event,
         blocked_activity.state AS blocked_state,
         blocking_activity.state AS blocking_state,
         blocked_locks.locktype AS blocked_locktype,
         blocking_locks.locktype AS blocking_locktype,
         blocked_activity.query AS blocked_statement,
         blocking_activity.query AS blocking_statement
    FROM pg_catalog.pg_locks blocked_locks
    JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks blocking_locks
        ON blocking_locks.locktype = blocked_locks.locktype
        AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
    WHERE NOT blocked_locks.GRANTED;
```

Todas as funções de API de bloqueio consultivo têm dois conjuntos de argumentos, um argumento `bigint` ou dois argumentos `integer`:
+ Para as funções de API com um único argumento `bigint`, os 32 bits superiores estão em `pg_locks.classid` e os 32 bits inferiores estão em `pg_locks.objid`.
+ Para as funções da API com dois argumentos `integer`, o primeiro argumento é `pg_locks.classid` e o segundo é `pg_locks.objid`.

O valor `pg_locks.objsubid` indica qual formato de API foi utilizado: `1` significa um argumento `bigint`; `2`significa dois argumentos `integer`.