powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / ExclusiveLock - норма?
11 сообщений из 11, страница 1 из 1
ExclusiveLock - норма?
    #39535619
acidophilus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый вечер.


Смотрю в:

[SRC sql]SELECT relation::regclass,* FROM pg_locks[/SR0C]


вижу несколько сессий с "ExclusiveLock" и locktype "virtualxid".



Насколько понял, это "подготовленные транзакции".


Скажите, это нормально они все "ExclusiveLock" создают?

И как понять какой объект БД они блокируют?
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39535622
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
acidophilus,

Это нормально, читайте про типы локов: https://www.postgresql.org/docs/current/static/explicit-locking.html

Объекты все есть в представлении в виде ID.
Т.к. это глобальное представление, то увидеть названия таблиц можно только подключившись к соответствующей базе.
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39535624
acidophilus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovacidophilus,

Это нормально, читайте про типы локов: https://www.postgresql.org/docs/current/static/explicit-locking.html

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

Спасибо, почитаю.

Но id у них пустой.
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39535658
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
acidophilus,

Есть там ID:
Код: plaintext
1.
locktype=virtualxid
virtualxid=54/1642395
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39558210
acidophilus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovacidophilus,

Есть там ID:
Код: plaintext
1.
locktype=virtualxid
virtualxid=54/1642395



А как найти что это за объект БД?


Например, получаю virtualxid
"121/100324"

А SELECT 100324::oid::regclass ни в одной БД не выводит название таблицы.
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39558250
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
acidophilus,

virtualxid — это идентификатор виртуальной транзакции, а не объект в базе.
Для объекта будет не-NULL-увым поле `relation`.
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39558283
acidophilus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovacidophilus,

virtualxid — это идентификатор виртуальной транзакции, а не объект в базе.
Для объекта будет не-NULL-увым поле `relation`.

Подскажите пожалуйста, как понять что блокируется?

Просто в БД висят десятки таких сессий
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39558292
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
acidophilus,

Рекурсивный запрос в конце поста: http://blog.postgresql-consulting.com/2017/10/deep-dive-into-postgres-stats.html
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39558307
acidophilus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovacidophilus,

Рекурсивный запрос в конце поста: http://blog.postgresql-consulting.com/2017/10/deep-dive-into-postgres-stats.html


Спасибо.




Однако, ничего не выводит запрос:


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
WITH RECURSIVE l AS (
  SELECT pid, locktype, mode, granted,
 ROW(locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid) obj
  FROM pg_locks
), pairs AS (
  SELECT w.pid waiter, l.pid locker, l.obj, l.mode
  FROM l w
  JOIN l ON l.obj IS NOT DISTINCT FROM w.obj AND l.locktype=w.locktype AND NOT l.pid=w.pid AND l.granted
  WHERE NOT w.granted
), tree AS (
  SELECT l.locker pid, l.locker root, NULL::record obj, NULL AS mode, 0 lvl, locker::text path, array_agg(l.locker) OVER () all_pids
  FROM ( SELECT DISTINCT locker FROM pairs l WHERE NOT EXISTS (SELECT 1 FROM pairs WHERE waiter=l.locker) ) l
  UNION ALL
  SELECT w.waiter pid, tree.root, w.obj, w.mode, tree.lvl+1, tree.path||'.'||w.waiter, all_pids || array_agg(w.waiter) OVER ()
  FROM tree JOIN pairs w ON tree.pid=w.locker AND NOT w.waiter = ANY ( all_pids )
)
SELECT (clock_timestamp() - a.xact_start)::interval(3) AS ts_age,
       replace(a.state, 'idle in transaction', 'idletx') state,
       (clock_timestamp() - state_change)::interval(3) AS change_age,
       a.datname,tree.pid,a.usename,a.client_addr,lvl,
       (SELECT count(*) FROM tree p WHERE p.path ~ ('^'||tree.path) AND NOT p.path=tree.path) blocked,
       repeat(' .', lvl)||' '||left(regexp_replace(query, '\s+', ' ', 'g'),100) query
FROM tree
JOIN pg_stat_activity a USING (pid)
ORDER BY path;
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39558329
Павел Лузанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
acidophilusА как найти что это за объект БД?


Например, получаю virtualxid
"121/100324"

А SELECT 100324::oid::regclass ни в одной БД не выводит название таблицы.

Строки с locktype=virtualxid ничего не блокируют.
Каждый раз когда начинается транзакция, в pg_locks добавляется эта строчка и удаляется по завершении транзакции.
Строка нужна для того, чтобы другие транзакции знали что эта транзакция еще живая и не завершена.

Хотя документация говорит, что другие транзакции всё-таки могут за неё цепляться:
"На протяжении транзакции серверный процесс удерживает исключительную блокировку виртуального идентификатора транзакции. Если транзакции назначается постоянный идентификатор (что обычно происходит, только если транзакция изменяет состояние базы данных), он также удерживает до её завершения блокировку этого постоянного идентификатора. Когда процесс находит необходимым ожидать именно какую-то другую транзакцию, он делает это, запрашивая разделяемую блокировку для идентификатора этой транзакции ( виртуального или постоянного, в зависимости от ситуации ). Этот запрос будет выполнен, только когда другая транзакция завершится и освободит свои блокировки."
...
Рейтинг: 0 / 0
ExclusiveLock - норма?
    #39562708
Павел Лузанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Оставлю здесь, вдруг еще пригодится.

Захотелось всё-таки разобраться зачем в pg_locks создаются строки с locktype=virtualxid.
Что это за ситуации, когда транзакция еще не получившая "настоящий" номер (т.е. только читающая) может кого-то заблокировать.

Вот что нашлось в исходниках :
"Every transaction takes a lock on its own virtual transaction ID. Currently, the only operations that wait for these locks are CREATE INDEX CONCURRENTLY and Hot Standby (in the case of a conflict), so most VXID locks are taken and released by the owner without anyone else needing to care."

Теперь идем в документацию на CREATE INDEX и читаем как выполняется CREATE INDEX CONCURRENTLY:
"При параллельном построении индекса он попадает в системный каталог в одной транзакции, затем ещё два сканирования таблицы выполняются в двух других транзакциях. Перед каждым сканированием таблицы процедура построения индекса должна ждать завершения текущих транзакций, модифицировавших эту таблицу. После второго сканирования также необходимо дожидаться завершения всех транзакций, получивших снимок (см. Главу 13) перед вторым сканированием ."

Вот оно что. Теперь можно и тестовый пример сделать.
В первой транзакции с уровнем изоляции REPEATABLE READ (чтобы снимок подольше оставался) прочитаем строки из таблицы. А во второй после этого попытаемся создать индекс.

Первый сеанс:
Код: sql
1.
2.
3.
4.
5.
6.
7.
postgres=# begin isolation level repeatable read ;
BEGIN
postgres=# select * from t;
 id 
----
  1
(1 row)


Второй сеанс:
Код: sql
1.
postgres=# create index CONCURRENTLY t_idx on t(id);


И второй сеанс повисает.


Теперь смотрим из третьего сеанса на блокировки:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
postgres=# select pid, locktype, virtualxid, granted, relation::regclass, mode
 from pg_locks
 where pid <> pg_backend_pid() order by pid;
 pid  |  locktype  | virtualxid | granted | relation |           mode           
------+------------+------------+---------+----------+--------------------------
 4185 | relation   |            | t       | t        | AccessShareLock
  4185 | virtualxid | 3/177      | t       |          | ExclusiveLock 
 6794 | relation   |            | t       | t_idx    | RowExclusiveLock
 6794 | virtualxid | 4/255      | t       |          | ExclusiveLock
  6794 | virtualxid | 3/177      | f       |          | ShareLock 
 6794 | relation   |            | t       | t        | ShareUpdateExclusiveLock
(6 rows)
Действительно, 5 строка "зацепилась" за вторую.

Кстати, вышеупомянутый запрос Виктора эту блокировку, разумеется, тоже покажет:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
postgres=# WITH RECURSIVE l AS (
postgres(#   SELECT pid, locktype, mode, granted,
postgres(#  ROW(locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid) obj
postgres(#   FROM pg_locks
postgres(# ), pairs AS (
postgres(#   SELECT w.pid waiter, l.pid locker, l.obj, l.mode
postgres(#   FROM l w
postgres(#   JOIN l ON l.obj IS NOT DISTINCT FROM w.obj AND l.locktype=w.locktype AND NOT l.pid=w.pid AND l.granted
postgres(#   WHERE NOT w.granted
postgres(# ), tree AS (
postgres(#   SELECT l.locker pid, l.locker root, NULL::record obj, NULL AS mode, 0 lvl, locker::text path, array_agg(l.locker) OVER () all_pids
postgres(#   FROM ( SELECT DISTINCT locker FROM pairs l WHERE NOT EXISTS (SELECT 1 FROM pairs WHERE waiter=l.locker) ) l
postgres(#   UNION ALL
postgres(#   SELECT w.waiter pid, tree.root, w.obj, w.mode, tree.lvl+1, tree.path||'.'||w.waiter, all_pids || array_agg(w.waiter) OVER ()
postgres(#   FROM tree JOIN pairs w ON tree.pid=w.locker AND NOT w.waiter = ANY ( all_pids )
postgres(# )
postgres-# SELECT (clock_timestamp() - a.xact_start)::interval(3) AS ts_age,
postgres-#        replace(a.state, 'idle in transaction', 'idletx') state,
postgres-#        (clock_timestamp() - state_change)::interval(3) AS change_age,
postgres-#        a.datname,tree.pid,a.usename,a.client_addr,lvl,
postgres-#        (SELECT count(*) FROM tree p WHERE p.path ~ ('^'||tree.path) AND NOT p.path=tree.path) blocked,
postgres-#        repeat(' .', lvl)||' '||left(regexp_replace(query, '\s+', ' ', 'g'),100) query
postgres-# FROM tree
postgres-# JOIN pg_stat_activity a USING (pid)
postgres-# ORDER BY path;
    ts_age    | state  |  change_age  | datname  | pid  | usename  | client_addr | lvl | blocked |                    query                     
--------------+--------+--------------+----------+------+----------+-------------+-----+---------+----------------------------------------------
 00:03:49.046 | idletx | 00:03:45.447 | postgres | 4185 | postgres |             |   0 |       1 |  select * from t;
 00:03:18.285 | active | 00:03:18.285 | postgres | 6794 | postgres |             |   1 |       0 |  . create index CONCURRENTLY t_idx on t(id);
(2 rows)


Пример с конфликтом на hot standby делать лениво.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / ExclusiveLock - норма?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]