52.12. pg_locks
#
Представление pg_locks
даёт доступ к информации о блокировках, удерживаемых активными процессами на сервере баз данных. Подробнее блокировки рассматриваются в Главе 13.
Представление pg_locks
содержит одну строку для каждого активного блокируемого объекта, запрошенного режима блокировки и блокирующего процесса. Таким образом, один и тот же блокируемый объект может фигурировать в этом представлении неоднократно, если его блокируют или ожидают блокировки несколько процессов. Однако объекты, свободные от блокировок, в этом представлении отсутствуют вовсе.
Существует несколько различных типов блокируемых объектов: отношения целиком (например, таблицы), отдельные страницы отношений, отдельные кортежи отношений, идентификаторы транзакций (виртуальные и постоянные) и произвольные объекты баз данных (идентифицируемые по OID класса и OID объекта, так же как в pg_description
или pg_depend
). Кроме того, в виде отдельного блокируемого объекта представлено право расширения отношения, как и право изменения значения pg_database
.datfrozenxid
. Также могут быть установлены «рекомендательные» блокировки, не имеющие предопределённого значения.
Таблица 52.12. Столбцы pg_locks
Тип столбца Описание |
---|
Тип блокируемого объекта: |
OID базы данных, к которой относится цель блокировки, ноль, если это разделяемый объект, либо NULL, если целью является идентификатор транзакции |
OID отношения, являющегося целью блокировки, либо NULL, если цель блокировки — не отношение или часть отношения |
Номер страницы в отношении, являющейся целью блокировки, либо NULL, если цель блокировки — не страница или кортеж отношения |
Номер кортежа на странице, являющегося целью блокировки, либо NULL, если цель блокировки — не кортеж |
Виртуальный идентификатор транзакции, являющийся целью блокировки, либо |
Идентификатор транзакции, являющийся целью блокировки, либо |
OID системного каталога, содержащего цель блокировки, либо NULL, если цель блокировки — не обычный объект базы данных |
OID цели блокировки в соответствующем системном каталоге, либо NULL, если цель блокировки — не обычный объект базы данных |
Номер столбца, являющегося целью блокировки (на саму таблицу указывают |
Виртуальный идентификатор транзакции, удерживающей или ожидающей блокировку |
Идентификатор серверного процесса (PID, Process ID), удерживающего или ожидающего эту блокировку, либо NULL, если блокировка удерживается подготовленной транзакцией |
Название режима блокировки, которая удерживается или запрашивается этим процессом (см. Подраздел 13.3.1 и Подраздел 13.2.3) |
True, если блокировка получена, и false, если она ожидается |
True, если блокировка получена по короткому пути, и false, если она получена через основную таблицу блокировок |
Время, когда серверный процесс начал ожидать блокировку, или NULL, если блокировка получена. Обратите внимание, что сразу после начала ожидания в этом поле может кратковременно наблюдаться NULL, при том что в |
Признак granted
устанавливается в строке, представляющей блокировку, удерживаемую указанным процессом. Если он сброшен, этот процесс ждёт блокировки, из чего следует что как минимум один другой процесс удерживает или ожидает блокировку того же объекта в конфликтующем режиме. Ожидающий процесс будет приостановлен до освобождения другой блокировки (или выявления ситуации взаимоблокировки). Один процесс в один момент времени может ожидать получения максимум одной блокировки.
На протяжении транзакции серверный процесс удерживает исключительную блокировку виртуального идентификатора транзакции. Если транзакции назначается постоянный идентификатор (что обычно происходит, только если транзакция изменяет состояние базы данных), он также удерживает до её завершения блокировку этого постоянного идентификатора. Когда процесс находит необходимым ожидать именно какую-то другую транзакцию, он делает это, запрашивая разделяемую блокировку для идентификатора этой транзакции (виртуального или постоянного, в зависимости от ситуации). Этот запрос будет выполнен, только когда другая транзакция завершится и освободит свои блокировки.
Хотя кортежи тоже представляют собой блокируемый объект, информация о блокировках строк хранится на диске, а не в памяти, поэтому такие блокировки обычно не показываются в этом представлении. Если процесс ожидает блокировки на уровне строки, он обычно виден в нём как ожидающий постоянного идентификатора транзакции текущего владельца этой блокировки.
Блокировка спекулятивного добавления состоит из идентификатора транзакции и маркера спекулятивного добавления. Маркер спекулятивного добавления отображается в столбце objid
.
Рекомендательные блокировки могут быть получены по ключам, состоящим из одного значения bigint
или из двух значений integer. Старшая половина bigint
выводится в столбце classid
, а младшая половина в столбце objid
, и objsubid
равен 1. Исходное значение bigint
может быть восстановлено выражением (classid::bigint << 32) | objid::bigint
. Для ключей integer первая часть ключа находится в classid
, а вторая часть в objid
, и objsubid
равна 2. Конкретное предназначение этих ключей определяет пользователь. Рекомендательные блокировки существуют в рамках базы данных, поэтому столбец database
имеет значение для таких блокировок.
В параллельном режиме используются блокировки применения транзакции при логической репликации. Идентификатор удалённой транзакции отображается в столбце transactionid
. Столбец objsubid
показывает подтип блокировки: 0 — блокировка для синхронизации набора изменений, 1 — блокировка для ожидания завершения транзакции, чтобы обеспечить порядок фиксации.
Представление 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.69).
В представлении pg_locks
показываются данные и из менеджера обычных блокировок, и из менеджера предикатных блокировок, которые являются отдельными механизмами; кроме того, менеджер обычных блокировок подразделяет свои блокировки на обычные и полученные быстрым путём. Абсолютная согласованность всех этих данных не гарантируется. При обращении к этому представлению данные блокировок по быстрому пути (с fastpath
= true
) собираются по очереди с каждого серверного процесса, без замораживания состояния всего менеджера блокировок, так что существует возможность, что в процессе сбора этой информации блокировки будут освобождены или получены. Заметьте однако, что эти блокировки не должны конфликтовать с любыми другими актуальными блокировками. После того как от всех процессов получены блокировки по быстрому пути, менеджер обычных блокировок замораживается целиком и информация обо всех оставшихся блокировках собирается в атомарной операции. После размораживания этого менеджера, также замораживается менеджер предикатных блокировок, и информация об этих блокировках собирается атомарно. Таким образом, за исключением блокировок по быстрому пути, каждый менеджер блокировок выдаёт согласованный набор результатов, но так как мы не блокируем оба этих менеджера одновременно, блокировки могут быть получены или освобождены после того, как опрашивается менеджер обычных блокировок, и до того, как опрашивается менеджер предикатных блокировок.
Блокировка менеджера обычных или предикатных блокировок может отразиться на производительности базы данных, если обращаться к этому представлению часто. Эта блокировка удерживается не дольше, чем необходимо для получения данных от менеджеров, но это не исключает возможность снижения производительности.
7.3. Select Lists
As shown in the previous section, the table expression in the SELECT
command constructs an intermediate virtual table by possibly combining tables, views, eliminating rows, grouping, etc. This table is finally passed on to processing by the select list. The select list determines which columns of the intermediate table are actually output.
7.3.1. Select-List Items
The simplest kind of select list is *
which emits all columns that the table expression produces. Otherwise, a select list is a comma-separated list of value expressions (as defined in Section 4.2). For instance, it could be a list of column names:
SELECT a, b, c FROM ...
The columns names a
, b
, and c
are either the actual names of the columns of tables referenced in the FROM
clause, or the aliases given to them as explained in Section 7.2.1.2. The name space available in the select list is the same as in the WHERE
clause, unless grouping is used, in which case it is the same as in the HAVING
clause.
If more than one table has a column of the same name, the table name must also be given, as in:
SELECT tbl1.a, tbl2.a, tbl1.b FROM ...
When working with multiple tables, it can also be useful to ask for all the columns of a particular table:
SELECT tbl1.*, tbl2.a FROM ...
See Section 8.16.5 for more about the table_name
.*
notation.
If an arbitrary value expression is used in the select list, it conceptually adds a new virtual column to the returned table. The value expression is evaluated once for each result row, with the row's values substituted for any column references. But the expressions in the select list do not have to reference any columns in the table expression of the FROM
clause; they can be constant arithmetic expressions, for instance.
7.3.2. Column Labels
The entries in the select list can be assigned names for subsequent processing, such as for use in an ORDER BY
clause or for display by the client application. For example:
SELECT a AS value, b + c AS sum FROM ...
If no output column name is specified using AS
, the system assigns a default column name. For simple column references, this is the name of the referenced column. For function calls, this is the name of the function. For complex expressions, the system will generate a generic name.
The AS
keyword is optional, but only if the new column name does not match any PostgreSQL keyword (see Appendix C). To avoid an accidental match to a keyword, you can double-quote the column name. For example, VALUE
is a keyword, so this does not work:
SELECT a value, b + c AS sum FROM ...
but this does:
SELECT a "value", b + c AS sum FROM ...
For protection against possible future keyword additions, it is recommended that you always either write AS
or double-quote the output column name.
Note
The naming of output columns here is different from that done in the FROM
clause (see Section 7.2.1.2). It is possible to rename the same column twice, but the name assigned in the select list is the one that will be passed on.
7.3.3. DISTINCT
After the select list has been processed, the result table can optionally be subject to the elimination of duplicate rows. The DISTINCT
key word is written directly after SELECT
to specify this:
SELECT DISTINCT select_list
...
(Instead of DISTINCT
the key word ALL
can be used to specify the default behavior of retaining all rows.)
Obviously, two rows are considered distinct if they differ in at least one column value. Null values are considered equal in this comparison.
Alternatively, an arbitrary expression can determine what rows are to be considered distinct:
SELECT DISTINCT ON (expression
[,expression
...])select_list
...
Here expression
is an arbitrary value expression that is evaluated for all rows. A set of rows for which all the expressions are equal are considered duplicates, and only the first row of the set is kept in the output. Note that the “first row” of a set is unpredictable unless the query is sorted on enough columns to guarantee a unique ordering of the rows arriving at the DISTINCT
filter. (DISTINCT ON
processing occurs after ORDER BY
sorting.)
The DISTINCT ON
clause is not part of the SQL standard and is sometimes considered bad style because of the potentially indeterminate nature of its results. With judicious use of GROUP BY
and subqueries in FROM
, this construct can be avoided, but it is often the most convenient alternative.