Rom*_*man 40 sql postgresql locking
我想不断跟踪postgres中的相互锁定.
我遇到了Locks Monitoring文章并尝试运行以下查询:
SELECT bl.pid AS blocked_pid,
a.usename AS blocked_user,
kl.pid AS blocking_pid,
ka.usename AS blocking_user,
a.query AS blocked_statement
FROM pg_catalog.pg_locks bl
JOIN pg_catalog.pg_stat_activity a ON a.pid = bl.pid
JOIN pg_catalog.pg_locks kl ON kl.transactionid = bl.transactionid AND kl.pid != bl.pid
JOIN pg_catalog.pg_stat_activity ka ON ka.pid = kl.pid
WHERE NOT bl.granted;
Run Code Online (Sandbox Code Playgroud)
不幸的是,它永远不会返回非空结果集.如果我将给定查询简化为以下形式:
SELECT bl.pid AS blocked_pid,
a.usename AS blocked_user,
a.query AS blocked_statement
FROM pg_catalog.pg_locks bl
JOIN pg_catalog.pg_stat_activity a ON a.pid = bl.pid
WHERE NOT bl.granted;
Run Code Online (Sandbox Code Playgroud)
然后它返回等待获取锁的查询.但我无法改变它,以便它可以返回阻止和阻止查询.
有任何想法吗?
a_h*_*ame 53
从9.6开始,这更容易,因为它引入了pg_blocking_pids()
查找阻止另一个会话的会话的功能.
所以你可以使用这样的东西:
select pid,
usename,
pg_blocking_pids(pid) as blocked_by,
query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
Run Code Online (Sandbox Code Playgroud)
Dev*_*evi 31
从这篇关于Postgres查询锁的优秀文章中,可以从以下查询中获取阻止查询和阻止查询及其信息.
CREATE VIEW lock_monitor AS(
SELECT
COALESCE(blockingl.relation::regclass::text,blockingl.locktype) as locked_item,
now() - blockeda.query_start AS waiting_duration, blockeda.pid AS blocked_pid,
blockeda.query as blocked_query, blockedl.mode as blocked_mode,
blockinga.pid AS blocking_pid, blockinga.query as blocking_query,
blockingl.mode as blocking_mode
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
AND blockinga.datid = blockeda.datid
WHERE NOT blockedl.granted
AND blockinga.datname = current_database()
);
SELECT * from lock_monitor;
Run Code Online (Sandbox Code Playgroud)
由于查询很长但很有用,因此文章作者为其创建了一个视图,以简化其用法.
M. *_*put 23
如何显示所有被阻止的查询。
select pid,
usename,
pg_blocking_pids(pid) as blocked_by,
query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
Run Code Online (Sandbox Code Playgroud)
您可以使用以下命令终止被阻止的查询。
SELECT pg_cancel_backend(a.pid), pg_terminate_backend(a.pid);
Run Code Online (Sandbox Code Playgroud)
您可以使用它终止所有被阻止的查询。
SELECT pg_cancel_backend(a.pid), pg_terminate_backend(a.pid)
FROM( select pid,
usename,
pg_blocking_pids(pid) as blocked_by,
query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0) a
Run Code Online (Sandbox Code Playgroud)
小智 8
Postgres 有一个非常丰富的系统目录,通过 SQL 表公开。PG 的统计收集器是一个子系统,支持收集和报告有关服务器活动的信息。
现在要找出阻塞 PID,您可以简单地查询pg_stat_activity
.
select pg_blocking_pids(pid) as blocked_by
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
Run Code Online (Sandbox Code Playgroud)
要获取阻塞PID对应的查询,您可以自连接或将其用作子查询中的where子句。
SELECT query
FROM pg_stat_activity
WHERE pid IN (select unnest(pg_blocking_pids(pid)) as blocked_by from pg_stat_activity where cardinality(pg_blocking_pids(pid)) > 0);
Run Code Online (Sandbox Code Playgroud)
注意:由于pg_blocking_pids(pid)
返回一个 Integer[],所以unnest
在WHERE pid IN
子句中使用它之前需要它。
寻找缓慢的查询有时会很乏味,所以要有耐心。狩猎快乐。
小智 8
对于早于 postgresql 9.6 的 postgresql 版本,它没有pg_blocking_pids
函数\xef\xbc\x8c,您可以使用以下查询来查找阻塞查询和阻塞查询。
SELECT w.query AS waiting_query,\n w.pid AS waiting_pid,\n w.usename AS waiting_user,\n now() - w.query_start AS waiting_duration,\n l.query AS locking_query,\n l.pid AS locking_pid,\n l.usename AS locking_user,\n t.schemaname || \'.\' || t.relname AS tablename,\n now() - l.query_start AS locking_duration\nFROM pg_stat_activity w\n JOIN pg_locks l1 ON w.pid = l1.pid AND NOT l1.granted\n JOIN pg_locks l2 ON l1.relation = l2.relation AND l2.granted\n JOIN pg_stat_activity l ON l2.pid = l.pid\n JOIN pg_stat_user_tables t ON l1.relation = t.relid\nWHERE w.waiting;\n
Run Code Online (Sandbox Code Playgroud)\n
对a_horse_with_no_name答案的这种修改将为您提供阻塞查询,而不仅仅是阻塞的会话:
SELECT
activity.pid,
activity.usename,
activity.query,
blocking.pid AS blocking_id,
blocking.query AS blocking_query
FROM pg_stat_activity AS activity
JOIN pg_stat_activity AS blocking ON blocking.pid = ANY(pg_blocking_pids(activity.pid));
Run Code Online (Sandbox Code Playgroud)
其他人已经回答了您的查询,但我遇到了某些情况:有很多查询相互阻塞,我想找到每个被阻止会话的主要阻止程序会话。
第一个例子:会话 5 被会话 4 阻塞,4 正在等待 3 和 2,而 3 和 2 正在等待会话 1。
5->4->{3,2}->1
Run Code Online (Sandbox Code Playgroud)
在这种情况下,第一阶段是真正的问题,一旦解决了,其他人就会照顾好自己。
所以我想要一个查询,它将显示如下结果:
被阻止的 pid | 拦截器 pid |
---|---|
5 | 1 |
4 | 1 |
3 | 1 |
2 | 1 |
因此,如果存在任何链锁定会话,此查询将向您显示每个被阻止会话的主要阻止程序会话。
;with recursive
find_the_source_blocker as (
select pid
,pid as blocker_id
from pg_stat_activity pa
where pa.state<>'idle'
and array_length(pg_blocking_pids(pa.pid), 1) is null
union all
select
t.pid as pid
,f.blocker_id as blocker_id
from find_the_source_blocker f
join ( SELECT
act.pid,
blc.pid AS blocker_id
FROM pg_stat_activity AS act
LEFT JOIN pg_stat_activity AS blc ON blc.pid = ANY(pg_blocking_pids(act.pid))
where act.state<>'idle') t on f.pid=t.blocker_id
)
select distinct
s.pid
,s.blocker_id
,pb.usename as blocker_user
,pb.query_start as blocker_start
,pb.query as blocker_query
,pt.query_start as trans_start
,pt.query as trans_query
from find_the_source_blocker s
join pg_stat_activity pb on s.blocker_id=pb.pid
join pg_stat_activity pt on s.pid=pt.pid
where s.pid<>s.blocker_id
Run Code Online (Sandbox Code Playgroud)
我发现其中经常缺少的一件事是查找行锁的能力。至少在我工作过的较大数据库上,行锁不会显示在 pg_locks 中(如果是的话,pg_locks 会大得多,并且没有真正的数据类型可以在该视图中正确显示锁定的行)。
我不知道有一个简单的解决方案,但通常我所做的是查看锁正在等待的表并搜索 xmax 小于那里存在的事务 id 的行。这通常为我提供了一个起点,但它需要动手操作,而且不适合自动化。
请注意,这显示了您对这些表上的行的未提交写入。提交后,这些行在当前快照中不可见。但对于大桌子来说,这是一个痛苦。