

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

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

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

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

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

## Context
<a name="apg-waits.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="apg-waits.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="apg-waits.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](#apg-waits.locktuple.actions.problem)
+ [Encontrar la sesión bloqueadora](#apg-waits.locktuple.actions.find-blocker)
+ [Reducir la concurrencia cuando es alta](#apg-waits.locktuple.actions.concurrency)
+ [Solucionar los cuellos de botella](#apg-waits.locktuple.actions.bottlenecks)

### Investigue la lógica de su aplicación
<a name="apg-waits.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="apg-waits.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. Para analizar eventos `Lock:tuple` pasados, utilice la función de Aurora `aurora_stat_backend_waits`. 

El siguiente ejemplo muestra todas las sesiones, con un filtro `tuple` y ordenadas 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
```

### Reducir la concurrencia cuando es alta
<a name="apg-waits.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="apg-waits.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.