PG 在發生 Locks 時,在一些較複雜的系統常常會看到 Blocked Chain 的狀況,B 使用者被 A 使用者查詢卡住,造成 C 使用者又被 B 使用者卡住,這種時候,雖然會查到很多 Locked 的狀況,但不需要全部砍掉,通常只要將源頭砍掉就會解開了,因此基於原本的 Blocked SQL 做加工。
Blocking 代表卡住造成別人無法執行查詢的 SQL,但這個 SQL 也有可能被前面的 SQL 卡住,而 Bloced 代表被卡住的 SQL,主要透過該 Session 的 Wait Event 來做判斷,如果為 Lock 就代表他有被別人卡住,如果是其他 Client Read 等等就代表正在順利執行或是 idle in transaction (通常是這個),則可以判斷是卡住的源頭。
查詢 SQL
SELECT
COALESCE(blockingl.relation::regclASs::text,blockingl.locktype) AS locked_item,
blockinga.pid AS blocking_pid,
blockinga.query AS blocking_query,
blockingl.mode AS blocking_mode,
CASE
WHEN blockinga.wait_event_type = 'Lock' THEN 'False'
ELSE 'True'
END AS leading_lock,
blockeda.pid AS blocked_pid,
blockeda.query AS blocked_query,
blockedl.mode AS blocked_mode,
now() - blockeda.query_start AS blocked_time
FROM pg_catalog.pg_locks blockedl
JOIN pg_stat_activity blockeda ON blockedl.pid = blockeda.pid
JOIN pg_catalog.pg_locks blockingl ON(
( (blockingl.transactionid=blockedl.transactionid) OR
(blockingl.relation=blockedl.relation AND blockingl.locktype=blockedl.locktype)
) AND blockedl.pid != blockingl.pid)
JOIN pg_stat_activity blockinga ON blockingl.pid = blockinga.pid
WHERE NOT blockedl.granted
order by leading_lock desc;
查詢結果
locked_item | blocking_pid | blocking_query | blocking_mode | leading_lock | blocked_pid | blocked_query | blocked_mode | blocked_time
------------------+--------------+-----------------------------+---------------------+--------------+-------------+----------------------------+---------------------+-----------------
pgbench_accounts | 548294 | truncate pgbench_accounts ; | ShareLock | True | 548398 | truncate pgbench_accounts; | AccessExclusiveLock | 00:04:29.498179
pgbench_accounts | 548294 | truncate pgbench_accounts ; | ShareLock | True | 548484 | truncate pgbench_accounts; | AccessExclusiveLock | 00:04:23.333006
pgbench_accounts | 548294 | truncate pgbench_accounts ; | AccessExclusiveLock | True | 548398 | truncate pgbench_accounts; | AccessExclusiveLock | 00:04:29.498179
pgbench_accounts | 548294 | truncate pgbench_accounts ; | AccessExclusiveLock | True | 548484 | truncate pgbench_accounts; | AccessExclusiveLock | 00:04:23.333006
pgbench_accounts | 548398 | truncate pgbench_accounts; | AccessExclusiveLock | False | 548484 | truncate pgbench_accounts; | AccessExclusiveLock | 00:04:23.333006
pgbench_accounts | 548484 | truncate pgbench_accounts; | AccessExclusiveLock | False | 548398 | truncate pgbench_accounts; | AccessExclusiveLock | 00:04:29.498179
參考資料:
https://ravenonhill.blogspot.com/2019/08/pgsql-who-blocks-my-query.html