

# Lock:tuple
<a name="wait-event.locktuple"></a>

El evento `Lock:tuple` se produce cuando un proceso backend espera adquirir un bloqueo sobre una tupla.

**Topics**
+ [Versiones del motor admitidas](#wait-event.locktuple.context.supported)
+ [Context](#wait-event.locktuple.context)
+ [Causas probables del aumento de las esperas](#wait-event.locktuple.causes)
+ [Acciones](#wait-event.locktuple.actions)

## Versiones del motor admitidas
<a name="wait-event.locktuple.context.supported"></a>

Esta información de eventos de espera es compatible con todas las versiones de RDS para PostgreSQL.

## Context
<a name="wait-event.locktuple.context"></a>

El evento `Lock:tuple` indica que un backend espera adquirir un bloqueo sobre una tupla mientras otro backend mantiene un bloqueo conflictivo sobre la misma tupla. La siguiente tabla ilustra un escenario en el que las sesiones generan el evento `Lock:tuple`.


|  Tiempo  |  Sesión 1  |  Sesión 2  |  Sesión 3  | 
| --- | --- | --- | --- | 
|  t1  |  Inicia una transacción.  |    |    | 
|  t2  |  Actualiza la fila 1.  |    |    | 
|  t3  |    |  Actualiza la fila 1. La sesión adquiere un bloqueo exclusivo sobre la tupla y luego espera a que la sesión 1 libere el bloqueo mediante la confirmación o reversión.  |    | 
|  t4  |    |    |  Actualiza la fila 1. La sesión espera a que la sesión 2 libere el bloqueo exclusivo en la tupla.  | 

También puede simular este evento de espera con la herramienta de punto de referencia `pgbench`. Configure un alto número de sesiones concurrentes para actualizar la misma fila en una tabla con un archivo SQL personalizado.

Para obtener más información sobre los modos de bloqueo conflictivos, consulte [E](https://www.postgresql.org/docs/current/explicit-locking.html) en la documentación de PostgreSQL. Para más información sobre `pgbench`, consulte [pgbench](https://www.postgresql.org/docs/current/pgbench.html) en la documentación de PostgreSQL.

## Causas probables del aumento de las esperas
<a name="wait-event.locktuple.causes"></a>

Cuando este evento aparece más de lo normal, lo que posiblemente indica un problema de rendimiento, las causas típicas son las siguientes:
+ Un gran número de sesiones concurrentes están intentando adquirir un bloqueo conflictivo para la misma tupla al ejecutar instrucciones `UPDATE` o `DELETE`.
+ Las sesiones altamente concurrentes se encuentran en ejecución con una instrucción `SELECT` que utiliza los modos de bloqueo `FOR UPDATE` o `FOR NO KEY UPDATE`.
+ Varios factores hacen que la aplicación o los grupos de conexión abran más sesiones para ejecutar las mismas operaciones. A medida que nuevas sesiones intentan modificar las mismas filas, la carga de la base de datos puede aumentar y puede aparecer `Lock:tuple`.

Para más información, consulte [Row-Level Locks](https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS) en la documentación de PostgreSQL.

## Acciones
<a name="wait-event.locktuple.actions"></a>

Recomendamos diferentes acciones en función de las causas del evento de espera.

**Topics**
+ [Investigue la lógica de su aplicación](#wait-event.locktuple.actions.problem)
+ [Encontrar la sesión bloqueadora](#wait-event.locktuple.actions.find-blocker)
+ [Reducir la concurrencia cuando es alta](#wait-event.locktuple.actions.concurrency)
+ [Solucionar los cuellos de botella](#wait-event.locktuple.actions.bottlenecks)

### Investigue la lógica de su aplicación
<a name="wait-event.locktuple.actions.problem"></a>

Verifique si una sesión del bloqueador se encuentra en el estado `idle in transaction` por mucho tiempo. Si es así, considere la posibilidad de finalizar la sesión del bloqueador como una solución a corto plazo. Puede utilizar la función `pg_terminate_backend`. Para más información sobre esta función, consulte [Server Signaling Functions](https://www.postgresql.org/docs/13/functions-admin.html#FUNCTIONS-ADMIN-SIGNAL) en la documentación de PostgreSQL.

Para una solución a largo plazo, haga lo siguiente:
+ Ajuste la lógica de la aplicación.
+ Utilice el parámetro `idle_in_transaction_session_timeout`. Este parámetro finaliza cualquier sesión con una transacción abierta que haya estado inactiva durante más tiempo del especificado. Para más información, consulte [Client Connection Defaults](https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-IDLE-IN-TRANSACTION-SESSION-TIMEOUT) en la documentación de PostgreSQL.
+ Utilice la confirmación automática en la medida de lo posible. Para más información, consulte [SET AUTOCOMMIT](https://www.postgresql.org/docs/current/ecpg-sql-set-autocommit.html) en la documentación de PostgreSQL.

### Encontrar la sesión bloqueadora
<a name="wait-event.locktuple.actions.find-blocker"></a>

Mientras se produce el evento de espera `Lock:tuple`, identifique el bloqueador y la sesión bloqueada mediante la búsqueda de los bloqueos que dependen unos de otros. Para más información, consulte la [Información sobre dependencia de bloqueos](https://wiki.postgresql.org/wiki/Lock_dependency_information) en el wiki de PostgreSQL. 

El siguiente ejemplo muestra todas las sesiones, con un filtro `tuple` y ordenadas por `wait_time`.

```
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;
```

### Reducir la concurrencia cuando es alta
<a name="wait-event.locktuple.actions.concurrency"></a>

El evento `Lock:tuple` puede producirse de manera frecuente, especialmente en un momento de carga de trabajo elevada. En esta situación, considere reducir la alta concurrencia para las filas muy ocupadas. A menudo, solo unas pocas filas controlan una cola o la lógica booleana, lo que hace que estas filas estén muy ocupadas.

Puede reducir la concurrencia mediante el uso de diferentes enfoques basados en los requisitos de la empresa, lógica de la aplicación y tipo de carga de trabajo. Por ejemplo, puede hacer lo siguiente:
+ Rediseñar la lógica de la tabla y los datos para reducir la alta concurrencia.
+ Cambiar la lógica de la aplicación para reducir la alta concurrencia entre filas.
+ Aprovechar y rediseñar las consultas con bloqueos entre filas.
+ Utilizar la cláusula `NOWAIT` con operaciones de reintento.
+ Considerar el uso de control de concurrencia optimista y de lógica de bloqueo híbrida.
+ Considerar la posibilidad de cambiar el nivel de aislamiento de la base de datos.

### Solucionar los cuellos de botella
<a name="wait-event.locktuple.actions.bottlenecks"></a>

La `Lock:tuple` producirse con cuellos de botella, como el agotamiento de la CPU o el uso máximo del ancho de banda de Amazon EBS. Para reducir los cuellos de botella, considere los siguientes enfoques:
+ Escalar verticalmente el tipo de clase de instancia.
+ Optimizar las consultas que consumen muchos recursos.
+ Cambiar la lógica de la aplicación.
+ Archivar los datos a los que rara vez se accede.