52.12. pg_locks#

52.12. pg_locks

52.12. pg_locks

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

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

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

Таблица 52.12. pg_locks Колонки

Тип столбца

Описание

locktype text

Тип блокируемого объекта: relation (отношение), extend (расширение), frozenid (замороженный идентификатор), page (страница), tuple (кортеж), transactionid (идентификатор транзакции), virtualxid (виртуальный идентификатор), spectoken (специальный компонент), object (объект), userlock (пользовательская блокировка) или advisory (консультативная блокировка). (См. также Таблица 27.11).

database oid (ссылается на pg_database.oid)

OID базы данных, в которой существует цель блокировки, или ноль, если цель является общим объектом, или null, если цель является идентификатором транзакции

relation oid (ссылается на pg_class.oid)

OID отношения, на которое нацелена блокировка, или null, если цель не является отношением или частью отношения

page int4

Номер страницы, на которую нацелена блокировка внутри отношения, или null, если целью не является страница отношения или кортеж

tuple int2

Номер кортежа, на который нацелена блокировка внутри страницы, или null, если целью не является кортеж

virtualxid text

Виртуальный идентификатор транзакции, на которую нацелена блокировка, или null, если целью не является виртуальный идентификатор транзакции

transactionid xid

ID транзакции, на которую нацелена блокировка, или null, если целью не является идентификатор транзакции

classid oid (ссылается на pg_class.oid)

OID системного каталога, содержащего цель блокировки, или null, если цель не является общим объектом базы данных

objid oid (ссылается на любой столбец OID)

OID цели блокировки в ее системном каталоге или null, если цель не является общим объектом базы данных

objsubid int2

Номер столбца, на который нацелена блокировка (теги classid и objid относятся к самой таблице), или ноль, если целью является какой-либо другой общий объект базы данных, или null, если целью не является общий объект базы данных

virtualtransaction text

Виртуальный идентификатор транзакции, который удерживает или ожидает эту блокировку

pid int4

Идентификатор процесса сервера, удерживающего или ожидающего эту блокировку, или null, если блокировка удерживается подготовленной транзакцией

mode text

Имя режима блокировки, удерживаемого или желаемого этим процессом (см. Раздел 13.3.1 и Раздел 13.2.3)

granted bool

True, если блокировка удерживается, false, если ожидается блокировка

fastpath bool

True, если блокировка была получена через быстрый путь, false, если была получена через основную таблицу блокировок

waitstart timestamptz

Время, когда процесс сервера начал ожидать этой блокировки, или null, если блокировка удерживается. Обратите внимание, что это может быть null в течение очень короткого периода времени после начала ожидания, даже если granted равно false.


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

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

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

Рекомендательные блокировки могут быть получены на ключах, состоящих из одного значения типа bigint или двух целочисленных значений. Ключ типа bigint отображается с его старшей половиной в столбце classid, его младшей половиной в столбце objid, и objsubid равным 1. Исходное значение типа bigint может быть восстановлено с помощью выражения (classid::bigint << 32) | objid::bigint. Целочисленные ключи отображаются с первым ключом в столбце 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 сам с собой, но это очень сложно сделать правильно в деталях. Такой запрос должен был бы закодировать знание о том, какие режимы блокировки конфликтуют друг с другом. Что хуже, представление pg_locks не раскрывает информацию о том, какие процессы находятся впереди других в очередях ожидания блокировки, а также информацию о том, какие процессы являются параллельными рабочими процессами, работающими от имени других клиентских сессий. Лучше использовать функцию pg_blocking_pids() (см. Таблица 9.66) для определения, за какими процессами заблокирован ожидающий процесс.

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

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