49.63. pg_locks
Представление pg_locks
даёт доступ к информации о блокировках, удерживаемых открытыми транзакциями на сервере баз данных. Подробнее блокировки рассматриваются в Главе 13.
Представление pg_locks
содержит одну строку для каждого активного блокируемого объекта, запрошенного режима блокировки и запрашивающей транзакции. Таким образом, один и тот же блокируемый объект может фигурировать в этом представлении неоднократно, если его блокируют или ожидают блокировки несколько транзакций. Однако объекты, свободные от блокировок, в этом представлении отсутствуют вовсе.
Существует несколько различных типов блокируемых объектов: отношения целиком (например, таблицы), отдельные страницы отношений, отдельные кортежи отношений, идентификаторы транзакций (виртуальные и постоянные) и произвольные объекты баз данных (идентифицируемые по OID класса и OID объекта, так же как в pg_description
или pg_depend
). Кроме того, в виде отдельного блокируемого объекта представлено право расширения отношения. Также могут быть установлены «рекомендательные» блокировки, не имеющие предопределённого значения.
Таблица 49.64. Столбцы pg_locks
Имя | Тип | Ссылки | Описание |
---|---|---|---|
locktype | text | Тип блокируемого объекта: relation (отношение), extend (расширение отношения), page (страница), tuple (кортеж), transactionid (идентификатор транзакции), virtualxid (виртуальный идентификатор), object (объект), userlock (пользовательская блокировка) или advisory (рекомендательная) | |
database | oid |
| OID базы данных, к которой относится цель блокировки, ноль, если это разделяемый объект, либо NULL, если целью является идентификатор транзакции |
relation | oid |
| OID отношения, являющегося целью блокировки, либо NULL, если цель блокировки — не отношение или часть отношения |
page | integer | Номер страницы в отношении, являющейся целью блокировки, либо NULL, если цель блокировки — не страница или кортеж отношения | |
tuple | smallint | Номер кортежа на странице, являющегося целью блокировки, либо NULL, если цель блокировки — не кортеж | |
virtualxid | text | Виртуальный идентификатор транзакции, являющийся целью блокировки, либо NULL, если цель блокировки — другой объект | |
transactionid | xid | Идентификатор транзакции, являющийся целью блокировки, либо NULL, если цель блокировки — другой объект | |
classid | oid |
| OID системного каталога, содержащего цель блокировки, либо NULL, если цель блокировки — не обычный объект базы данных |
objid | oid | любой столбец OID | OID цели блокировки в соответствующем системном каталоге, либо NULL, если цель блокировки — не обычный объект базы данных |
objsubid | smallint | Номер столбца, являющегося целью блокировки (на саму таблицу указывают classid и objid ), ноль, если это некоторый другой обычный объект базы данных, либо NULL, если цель не обычный объект | |
virtualtransaction | text | Виртуальный идентификатор транзакции, удерживающей или ожидающей блокировку | |
pid | integer | Идентификатор серверного процесса (PID, Process ID), удерживающего или ожидающего эту блокировку, либо NULL, если блокировка удерживается подготовленной транзакцией | |
mode | text | Название режима блокировки, которая удерживается или запрашивается этим процессом (см. Подраздел 13.3.1 и Подраздел 13.2.3) | |
granted | boolean | True, если блокировка получена, и false, если она ожидается | |
fastpath | boolean | True, если блокировка получена по короткому пути, и false, если она получена через основную таблицу блокировок |
Признак granted
устанавливается в строке, представляющей блокировку, удерживаемую указанной транзакцией. Если он сброшен, эта транзакция ждёт блокировки, из чего следует, что некоторая другая транзакция удерживает блокировку того же объекта в конфликтующем режиме. Ожидающая транзакция будет приостановлена до освобождения другой блокировки (или выявления ситуации взаимоблокировки). Одна транзакция в один момент времени может ожидать получения максимум одной блокировки.
Каждая транзакция удерживает исключительную блокировку для собственного виртуального идентификатора транзакции на всём своём протяжении. Если транзакции назначается постоянный идентификатор (что обычно происходит, только если транзакция изменяет состояние базы данных), она также удерживает до своего завершения блокировку этого постоянного идентификатора. Когда одна транзакция находит необходимым ожидать именно какую-то другую транзакцию, она делает это, запрашивая разделяемую блокировку для идентификатора другой транзакции (виртуального или постоянного, в зависимости от ситуации). Этот запрос будет выполнен, только когда другая транзакция завершится и освободит свои блокировки.
Хотя кортежи тоже представляют собой блокируемый объект, информация о блокировках строк хранится на диске, а не в памяти, поэтому такие блокировки обычно не показываются в этом представлении. Если транзакция ожидает блокировки на уровне строки, она обычно видна в нём как ожидающая постоянного идентификатора транзакции текущего владельца этой блокировки.
Рекомендательные блокировки могут быть получены по ключам, состоящим из одного значения bigint
или из двух значений integer. Старшая половина bigint
выводится в столбце classid
, а младшая половина в столбце objid
, и objsubid
равен 1. Исходное значение bigint
может быть восстановлено выражением (classid::bigint << 32) | objid::bigint
. Для ключей integer первая часть ключа находится в classid
, а вторая часть в objid
, и objsubid
равна 2. Конкретное предназначение этих ключей определяет пользователь. Рекомендательные блокировки существуют в рамках базы данных, поэтому столбец database
имеет значение для таких блокировок.
Представление pg_locks
даёт общую информацию по всем блокировкам в кластере баз данных, а не только по тем, что относятся к текущей базе. Хотя соединив relation
с pg_class
.oid
, можно получить заблокированные отношения, это будет работать корректно только для отношений в текущей базе данных (для тех, в блокировках которых столбец database
содержит OID текущей базы данных или ноль).
Соединив столбец pid
со столбцом pid
представления pg_stat_activity
, можно получить дополнительную информацию о сеансах, удерживающих блокировки, например так:
SELECT * FROM pg_locks pl LEFT JOIN pg_stat_activity psa ON pl.pid = psa.pid;
Также, если вы используете подготовленные транзакции, столбец virtualtransaction
можно соединить со столбцом transaction
представления pg_prepared_xacts
для получения дополнительной информации о подготовленных транзакциях, удерживающих блокировки. (Подготовленная транзакция не может ожидать блокировок, но она может продолжать удерживать блокировки, полученные ей в процессе выполнения.) Например:
SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx ON pl.virtualtransaction = '-1/' || ppx.transaction;
В представлении pg_locks
показываются данные и из менеджера обычных блокировок, и из менеджера предикатных блокировок, которые являются отдельными механизмами; кроме того, менеджер обычных блокировок подразделяет свои блокировки на обычные и полученные быстрым путём. Абсолютная согласованность всех этих данных не гарантируется. При обращении к этому представлению данные блокировок по быстрому пути (с fastpath
= true
) собираются по очереди с каждого серверного процесса, без замораживания состояния всего менеджера блокировок, так что существует возможность, что в процессе сбора этой информации блокировки будут освобождены или получены. Заметьте, однако, что эти блокировки не должны конфликтовать с любыми другими актуальными блокировками. После того как от всех процессов получены блокировки по быстрому пути, менеджер обычных блокировок замораживается целиком и информация обо всех оставшихся блокировках собирается в атомарной операции. После размораживания этого менеджера, также замораживается менеджер предикатных блокировок, и информация об этих блокировках собирается атомарно. Таким образом, за исключением блокировок по быстрому пути, каждый менеджер блокировок выдаёт согласованный набор результатов, но так как мы не блокируем оба этих менеджера одновременно, блокировки могут быть получены или освобождены после того, как опрашивается менеджер обычных блокировок, и до того, как опрашивается менеджер предикатных блокировок.
Блокировка менеджера обычных или предикатных блокировок может отразиться на производительности базы данных, если обращаться к этому представлению часто. Эта блокировка удерживается не дольше, чем необходимо для получения данных от менеджеров, но это не исключает возможность снижения производительности.