53.13. pg_locks #

La vista pg_locks proporciona acceso a información sobre los bloqueos retenidos por procesos activos dentro del servidor de base de datos. Consulta Chapter 13 para obtener más información sobre el bloqueo.

pg_locks contiene una fila por cada objeto bloqueable activo, modo de bloqueo solicitado y proceso relevante. Por lo tanto, el mismo objeto bloqueable puede aparecer muchas veces si múltiples procesos lo bloquean o esperan por él. Sin embargo, un objeto que actualmente no tiene bloqueos no aparecerá en absoluto.

Existen varios tipos distintos de objetos bloqueables: relaciones completas (por ejemplo, tablas), páginas individuales de relaciones, tuplas individuales de relaciones, ID de transacciones (tanto ID virtuales como permanentes) y objetos generales de la base de datos (identificados por OID de clase y OID de objeto, de la misma manera que en pg_description o pg_depend). Además, el derecho a extender una relación se representa como un objeto bloqueable separado, al igual que el derecho a actualizar pg_database.datfrozenxid. Además, se pueden tomar bloqueos advisory (consultivos) sobre números que tienen significados definidos por el usuario.

Table 53.13. pg_locks Columns

Tipo de columna

Descripción

locktype text

Tipo de objeto bloqueable: relation, extend, frozenid, page, tuple, transactionid, virtualxid, spectoken, object, userlock, advisory o applytransaction. (Consulta también Table 27.11).

database oid (references pg_database.oid)

OID de la base de datos en la que existe el objetivo de bloqueo, o cero si el objetivo es un objeto compartido, o nulo si el objetivo es un ID de transacción.

relation oid (references pg_class.oid)

OID de la relación a la que se dirige el bloqueo, o nulo si el objetivo no es una relación o parte de una relación.

page int4

Número de página al que se dirige el bloqueo dentro de la relación, o nulo si el objetivo no es una página de relación o tupla.

tuple int2

Número de tupla al que se dirige el bloqueo dentro de la página, o nulo si el objetivo no es una tupla.

virtualxid text

ID virtual de la transacción a la que se dirige el bloqueo, o nulo si el objetivo no es un ID de transacción virtual; consulta Chapter 67.

transactionid xid

ID de la transacción a la que se dirige el bloqueo, o nulo si el objetivo no es un ID de transacción; consulta Chapter 67.

classid oid (references pg_class.oid)

OID del catálogo del sistema que contiene el objetivo del bloqueo, o nulo si el objetivo no es un objeto de base de datos general.

objid oid (references any OID column)

OID del objetivo del bloqueo dentro de su catálogo del sistema, o nulo si el objetivo no es un objeto de base de datos general.

objsubid int2

Número de columna al que se dirige el bloqueo (los campos classid y objid se refieren a la tabla misma), o cero si el objetivo es algún otro objeto de base de datos general, o nulo si el objetivo no es un objeto de base de datos general.

virtualtransaction text

ID virtual de la transacción que retiene o espera este bloqueo.

pid int4

ID de proceso del proceso del servidor que retiene o espera este bloqueo, o nulo si el bloqueo lo retiene una transacción preparada.

mode text

Nombre del modo de bloqueo retenido o deseado por este proceso (consulta Section 13.3.1 y Section 13.2.3).

granted bool

True si se retiene el bloqueo, false si se espera el bloqueo.

fastpath bool

True si el bloqueo se tomó a través de fast path, false si se tomó a través de la tabla de bloqueos principal.

waitstart timestamptz

Hora a la que el proceso del servidor comenzó a esperar este bloqueo, o nulo si se retiene el bloqueo. Ten en cuenta que esto puede ser nulo durante un período de tiempo muy corto después de que comenzó la espera, aunque granted sea false.


granted es true en una fila que representa un bloqueo retenido por el proceso indicado. False indica que este proceso está esperando actualmente para adquirir este bloqueo, lo que implica que al menos otro proceso está reteniendo o esperando un modo de bloqueo en conflicto sobre el mismo objeto bloqueable. El proceso en espera dormirá hasta que se libere el otro bloqueo (o se detecte una situación de deadlock). Un solo proceso puede estar esperando para adquirir como máximo un bloqueo a la vez.

Durante la ejecución de una transacción, un proceso del servidor mantiene un bloqueo exclusivo sobre el ID de transacción virtual de la transacción. Si se asigna un ID permanente a la transacción (lo cual normalmente ocurre solo si la transacción cambia el estado de la base de datos), también mantiene un bloqueo exclusivo sobre el ID de transacción permanente de la transacción hasta que esta finaliza. Cuando un proceso considera necesario esperar específicamente a que finalice otra transacción, lo hace intentando adquirir un bloqueo compartido sobre el ID de la otra transacción (ya sea el ID virtual o el permanente, según la situación). Esto tendrá éxito solo cuando la otra transacción termine y libere sus bloqueos.

Aunque las tuplas son un tipo de objeto bloqueable, la información sobre los bloqueos a nivel de fila se almacena en el disco, no en la memoria, y por lo tanto los bloqueos a nivel de fila normalmente no aparecen en esta vista. Si un proceso está esperando un bloqueo a nivel de fila, normalmente aparecerá en la vista como en espera del ID de transacción permanente del poseedor actual de ese bloqueo de fila.

Un bloqueo de inserción especulativa consiste en un ID de transacción y un token de inserción especulativa. El token de inserción especulativa se muestra en la columna objid.

Los bloqueos consultivos (advisory locks) se pueden adquirir sobre claves que consisten en un único valor de tipo bigint o dos valores enteros. Una clave bigint se muestra con su mitad de orden superior en la columna classid, su mitad de orden inferior en la columna objid y objsubid igual a 1. El valor bigint original se puede volver a ensamblar con la expresión (classid::bigint << 32) | objid::bigint. Las claves enteras se muestran con la primera clave en la columna classid, la segunda clave en la columna objid y objsubid igual a 2. El significado real de las claves depende del usuario. Los bloqueos consultivos son locales para cada base de datos, por lo que la columna database es significativa para un bloqueo consultivo.

Los bloqueos de transacción de aplicación (apply transaction locks) se utilizan en modo paralelo para aplicar la transacción en la replicación lógica. El ID de la transacción remota se muestra en la columna transactionid. El campo objsubid muestra el subtipo de bloqueo, que es 0 para el bloqueo utilizado para sincronizar el conjunto de cambios, y 1 para el bloqueo utilizado para esperar a que finalice la transacción para garantizar el orden de confirmación (commit).

pg_locks proporciona una vista global de todos los bloqueos en el clúster de bases de datos, no solo de los relevantes para la base de datos actual. Aunque su columna relation se puede unir (join) a pg_class.oid para identificar relaciones bloqueadas, esto solo funcionará correctamente para relaciones en la base de datos actual (aquellas para las cuales la columna database es el OID de la base de datos actual o cero).

La columna pid se puede unir a la columna pid de la vista pg_stat_activity para obtener más información sobre la sesión que retiene o espera cada bloqueo, por ejemplo:

SELECT * FROM pg_locks pl LEFT JOIN pg_stat_activity psa
    ON pl.pid = psa.pid;

Además, si estás utilizando transacciones preparadas, la columna virtualtransaction se puede unir a la columna transaction de la vista pg_prepared_xacts para obtener más información sobre las transacciones preparadas que retienen bloqueos. (Una transacción preparada nunca puede estar esperando un bloqueo, pero continúa reteniendo los bloqueos que adquirió durante su ejecución). Por ejemplo:

SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
    ON pl.virtualtransaction = '-1/' || ppx.transaction;

Aunque es posible obtener información sobre qué procesos bloquean a qué otros procesos uniendo pg_locks consigo misma, esto es muy difícil de hacer correctamente en detalle. Tal consulta tendría que codificar el conocimiento sobre qué modos de bloqueo entran en conflicto con cuáles otros. Peor aún, la vista pg_locks no expone información sobre qué procesos están por delante de otros en las colas de espera de bloqueo, ni información sobre qué procesos son trabajadores paralelos que se ejecutan en nombre de qué otras sesiones de cliente. Es mejor utilizar la función pg_blocking_pids() (consulta Table 9.71) para identificar detrás de qué proceso(s) está bloqueado un proceso en espera.

La vista pg_locks muestra datos tanto del administrador de bloqueos regular como del administrador de bloqueos de predicados, que son sistemas separados; además, el administrador de bloqueos regular subdivide sus bloqueos en bloqueos regulares y de fast-path. No se garantiza que estos datos sean completamente consistentes. Cuando se consulta la vista, los datos sobre los bloqueos de fast-path (con fastpath = true) se recopilan de cada backend uno a la vez, sin congelar el estado de todo el administrador de bloqueos, por lo que es posible que se tomen o liberen bloqueos mientras se recopila la información. Ten en cuenta, sin embargo, que se sabe que estos bloqueos no entran en conflicto con ningún otro bloqueo actualmente activo. Después de haber consultado todos los backends para obtener los bloqueos de fast-path, el resto del administrador de bloqueos regular se bloquea como una unidad, y se recopila una instantánea (snapshot) consistente de todos los bloqueos restantes como una acción atómica. Después de desbloquear el administrador de bloqueos regular, el administrador de bloqueos de predicados se bloquea de manera similar y todos los bloqueos de predicados se recopilan como una acción atómica. Por lo tanto, con la excepción de los bloqueos de fast-path, cada administrador de bloqueos entregará un conjunto consistente de resultados, pero como no bloqueamos ambos administradores de bloqueos simultáneamente, es posible que se tomen o liberen bloqueos después de interrogar al administrador de bloqueos regular y antes de interrogar al administrador de bloqueos de predicados.

Bloquear el administrador de bloqueos regular y/o el de predicados podría tener algún impacto en el rendimiento de la base de datos si se accede a esta vista con mucha frecuencia. Los bloqueos se mantienen únicamente durante el tiempo mínimo necesario para obtener los datos de los administradores de bloqueos, pero esto no elimina por completo la posibilidad de un impacto en el rendimiento.