Lock:tuple
El evento Lock:tuple
se produce cuando un proceso backend espera adquirir un bloqueo sobre una tupla.
Versiones del motor admitidas
Esta información de eventos de espera es compatible con todas las versiones de RDS para PostgreSQL.
Context
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 Epgbench
, consulte pgbench
Causas probables del aumento de las esperas
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
oDELETE
. -
Las sesiones altamente concurrentes se encuentran en ejecución con una instrucción
SELECT
que utiliza los modos de bloqueoFOR UPDATE
oFOR 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
Acciones
Recomendamos diferentes acciones en función de las causas del evento de espera.
Temas
Investigue la lógica de su aplicación
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
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 Defaultsen 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
en la documentación de PostgreSQL.
Encontrar la sesión bloqueadora
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
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
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
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.