Перейти к основному содержимому

pg_locks

Представление pg_locks предоставляет доступ к информации о блокировках, принадлежащих активным процессам на сервере базы данных.

pg_locks содержит одну строку для каждого активного блокируемого объекта, запрашиваемого режима блокировки и соответствующего процесса. Таким образом, один и тот же блокируемый объект может появляться много раз, если несколько процессов удерживают или ожидают блокировки на нем. Однако объект, на который в данный момент не наложено ни одной блокировки, не появится вообще.

Существует несколько различных типов блокируемых объектов: целые отношения (например, таблицы), отдельные страницы отношений, отдельные кортежи отношений, идентификаторы транзакций (как виртуальные, так и постоянные) и общие объекты базы данных (идентифицируемые по OID класса и OID объекта, так же, как в pg_description или pg_depend). Кроме того, право на расширение отношения представлено в виде отдельного блокируемого объекта, как и право на обновление pg_database.datfrozenxid. Кроме того, «консультативные» блокировки могут накладываться на числа, имеющие определенные пользователем значения.

СтолбецТип данныхОписание
locktypetextТип блокируемого объекта: relation, extend, frozenid, page, tuple, transactionid, virtualxid, spectoken, object, userlock, advisory или applytransaction
databaseoid (ссылается на pg_database.oid)OID базы данных, в которой существует цель блокировки, или ноль, если цель является общим объектом, или ноль, если цель является идентификатором транзакции
relationoid (ссылается на pg_class.oid)OID отношения, являющегося объектом блокировки, или NULL, если объект не является отношением или частью отношения
pageint4Номер страницы, на которую направлена блокировка в отношении, или нулевой, если целевой страницей не является страница отношения или кортеж
tupleint2Число кортежей, на которые направлена блокировка на странице, или нулевое, если целевой кортеж не является кортежом
virtualxidtextВиртуальный идентификатор транзакции, на которую направлена блокировка, или нулевой, если целевой идентификатор не является виртуальным идентификатором транзакции; см. главу 74
transactionidxidИдентификатор транзакции, на которую направлена блокировка, или нулевой, если целевой идентификатор не является идентификатором транзакции; Глава 74
classidoid (ссылается на pg_class.oid)OID системного каталога, содержащего цель блокировки, или NULL, если цель не является общим объектом базы данных
objidoid (ссылается на любой столбец OID)OID цели блокировки в системном каталоге или NULL, если цель не является общим объектом базы данных
objsubidint2Номер столбца, на который нацелена блокировка (classid и objid относятся к самой таблице), или ноль, если целью является какой-либо другой общий объект базы данных, или ноль, если целью не является общий объект базы данных
virtualtransactiontextВиртуальный идентификатор транзакции, которая держит или ожидает эту блокировку
pidint4Идентификатор процесса серверного процесса, удерживающего или ожидающего эту блокировку, или нулевой, если блокировка удерживается подготовленной транзакцией
modetextИмя режима блокировки, удерживаемого или желаемого этим процессом
grantedboolTrue, если блокировка удерживается, false, если блокировка ожидается
fastpathboolTrue, если блокировка была выполнена с помощью fast path, false, если блокировка была выполнена с помощью основной таблицы блокировки
waitstarttimestamptzВремя, когда процесс сервера начал ждать этой блокировки, или нулевое, если блокировка удерживается. Обратите внимание, что оно может быть нулевым в течение очень короткого периода времени после начала ожидания, даже если предоставленное значение неверно

granted является true в ряду, представляющим блокировку, удерживаемую указанным процессом. False указывает на то, что этот процесс в настоящее время ждет получения этой блокировки, что означает, что хотя бы один другой процесс держит или ждет конфликтующего режима блокировки на том же блокируемом объекте. Процесс ожидания будет спать, пока не будет освобожден другой замок (или не будет обнаружена ситуация тупика). Один процесс может ждать получения максимум одной блокировки за один раз.

Во время выполнения транзакции серверный процесс держит эксклюзивную блокировку на виртуальном идентификаторе транзакции. Если транзакции присваивается постоянный идентификатор (что обычно происходит только в случае изменения состояния базы данных), он также удерживает эксклюзивную блокировку на постоянном идентификаторе транзакции до ее завершения. Если процесс считает необходимым специально дождаться завершения другой транзакции, он делает это, пытаясь получить блокировку доли на ID другой транзакции (виртуальный или постоянный ID, в зависимости от ситуации). Это удастся только тогда, когда другая транзакция завершится и снимет свои блокировки.

Хотя кортежи являются объектами с возможностью блокировки, информация о блокировках на уровне строки хранится на диске, а не в памяти, и поэтому блокировки на уровне строки обычно не отображаются в этом представлении. Если процесс ожидает блокировки на уровне строки, он обычно отображается в представлении как ожидающий постоянного идентификатора транзакции текущего владельца блокировки этой строки.

Консультативные блокировки могут быть получены на ключи, состоящие либо из одного значения bigint, либо из двух целочисленных значений. Ключ bigint отображается со старшей половиной в столбце classid, младшей половиной в столбце objid и objsubid равным 1. Оригинальное значение bigint может быть восстановлено с помощью выражения (classid::bigint << 32) | objid::bigint. Целочисленные ключи отображаются так: первый ключ в столбце classid, второй ключ в столбце objid, а objsubid равен 2. Фактическое значение ключей зависит от пользователя. Консультативные блокировки локальны для каждой базы данных, поэтому столбец базы данных имеет значение для консультативной блокировки.

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 с самим собой, это очень сложно сделать в деталях. Такой запрос должен содержать информацию о том, какие режимы блокировки конфликтуют с другими. Хуже того, представление pg_locks не предоставляет информацию о том, какие процессы опережают другие в очередях ожидания блокировок, а также информацию о том, какие процессы являются параллельными рабочими, работающими от имени других клиентских сессий. Лучше использовать функцию pg_blocking_pids(), чтобы определить, за каким процессом (процессами) заблокирован ожидающий процесс.

В представлении pg_locks отображаются данные как обычного менеджера блокировок, так и предикатного менеджера блокировок, которые являются отдельными системами; кроме того, обычный менеджер блокировок подразделяет свои блокировки на обычные и fast-path-блокировки. Эти данные не гарантируют полной согласованности. Когда представление запрашивается, данные о блокировках fast-path (с fastpath = true) собираются из каждого бэкенда по очереди, не замораживая состояние всего менеджера блокировок, поэтому во время сбора информации блокировки могут быть сняты или освобождены. Заметьте, однако, что эти блокировки заведомо не конфликтуют ни с какими другими блокировками, действующими в данный момент. После того как все бэкенды были запрошены на наличие блокировок быстрого пути, оставшаяся часть обычного менеджера блокировок блокируется как единое целое, и последовательный снимок всех оставшихся блокировок собирается как атомарное действие. После разблокировки менеджера обычных блокировок аналогичным образом блокируется менеджер предикатных блокировок, и все предикатные блокировки собираются как атомарное действие. Таким образом, за исключением блокировок быстрого пути, каждый менеджер блокировок будет выдавать согласованный набор результатов, но поскольку мы не блокируем оба менеджера блокировок одновременно, существует вероятность того, что блокировки будут сняты или освобождены после того, как мы опросим менеджер обычных блокировок, и до того, как мы опросим менеджер предикатных блокировок.

Блокировка менеджера регулярных и/или предикатных блокировок может оказать некоторое влияние на производительность базы данных, если к этому представлению обращаются очень часто. Блокировки удерживаются только в течение минимального времени, необходимого для получения данных от менеджеров блокировок, но это не полностью исключает возможность влияния на производительность.