fdo*_*4un 4 sql postgresql locking
我pg_try_advisory_lock()在Postgres 使用.
接下来的两个查询会锁定多个记录table1:
1)
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE
table2.id = 1
AND
pg_try_advisory_lock('table1'::regclass::integer, a.id)
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
但
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
Run Code Online (Sandbox Code Playgroud)
返回一条记录.
2)
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
JOIN table3 c ON b.table2_id = c.id
WHERE
table3.id = 1
AND
pg_try_advisory_lock('table1'::regclass::integer, a.id)
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
但是我pg_try_advisory_lock()只需要锁定一条记录.
怎么了?
UPD
但奇怪的是,当我运行以下查询时
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE
pg_try_advisory_lock('table1'::regclass::integer, a.id)
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)
Postgres只锁定一行.那么,Postgres扫描第一行然后停止?我不明白:它应扫描所有行然后将结果限制为一行,或不?
您在扫描的整个集合中每行调用pg_try_advisory_lock()一次(作为where子句中发生的过滤的一部分),而您只希望在查询返回的table1中每行调用一次.
您可以尝试使用子查询或CTE:
with rows as (
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
)
select rows.*
from rows
where pg_try_advisory_lock('table1'::regclass::integer, rows.id);
Run Code Online (Sandbox Code Playgroud)
但是不要依赖于它必然按预期工作:Postgres应该试图按照初始查询的方式重写它.
另一种可能性是,因为select语句的一部分在查询中很晚才被评估:
with rows as (
SELECT a.id,
pg_try_advisory_lock('table1'::regclass::integer, a.id) as locked
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
)
select rows.id
from rows
where rows.locked;
Run Code Online (Sandbox Code Playgroud)
实践中的真正问题是,pg_try_advisory_lock()您通常会在app land或函数中找到它,而不是像您正在进行的查询.说到这些,取决于你在做什么,你确定你不应该使用select … for update?
关于你的更新:
postgres扫描第一行然后停止?
是.由于limit 1,它会找到匹配并立即停止.但是,可能发生的是,它不会where根据您的查询以相同的顺序评估该子句.SQL不保证首先评估a <> 0部件a <> 0 and b / a > c.适用于您的情况,它不保证在a与a连接的行之后获得咨询锁定.