Todos los términos del glosario

Interbloqueo (deadlock)

¿Qué es un interbloqueo (deadlock) en PostgreSQL y cómo evitarlo?

Un interbloqueo ocurre cuando dos transacciones esperan cada una un bloqueo que tiene la otra. PostgreSQL lo detecta y cancela una de ellas; tomar los bloqueos en un orden consistente lo evita.

Un interbloqueo es un ciclo de esperas de bloqueos: la transacción A tiene un bloqueo que B necesita mientras B tiene un bloqueo que A necesita, así que ninguna puede continuar. PostgreSQL detecta estos ciclos automáticamente y los resuelve abortando una de las transacciones, que recibe un error deadlock detected.

La comprobación no se ejecuta en cada espera de bloqueo: una sesión primero espera deadlock_timeout (un segundo de forma predeterminada) antes de buscar un ciclo. La mejor defensa es bloquear los mismos objetos en el mismo orden en todas las transacciones, por ejemplo bloqueando las filas ordenadas por clave primaria, y mantener las transacciones cortas. El código que aún pueda encontrarse con un interbloqueo debe reintentar la transacción abortada.

Ejemplo

El ejemplo bloquea en una sola sentencia las dos filas que va a modificar, ordenadas por id, antes de actualizarlas. Cuando todas las transacciones que tocan estas filas hacen lo mismo, esperan su turno en lugar de caer en un interbloqueo.

CREATE TABLE ledger (id int PRIMARY KEY, balance int);
INSERT INTO ledger VALUES (1, 100), (2, 100);

SHOW deadlock_timeout;

BEGIN;
SELECT id FROM ledger WHERE id IN (1, 2) ORDER BY id FOR UPDATE;
UPDATE ledger SET balance = balance - 10 WHERE id = 1;
UPDATE ledger SET balance = balance + 10 WHERE id = 2;
COMMIT;

SQL simple para PostgreSQL 16 o 17 estándar, sin extensiones. Ejecútalo en una base de datos vacía que puedas descartar.

Fuentes

Documentación oficial de PostgreSQL (en inglés).

Términos relacionados