我在 Postgres 中使用 pg_try_advisory_lock()
。
接下来的两个查询锁定了 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;
但是
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
返回一条记录。
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;
但我需要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;
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);
但也不要依赖于它一定会按预期工作: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;
实践中真正的问题是 pg_try_advisory_lock()
是您通常会在应用程序领域或函数中找到的东西,而不是像您正在做的那样在查询中找到。说到这,取决于你在做什么,你确定你不应该使用 select … for update
?
关于您的更新:
postgres scans the very first row then stops?
是的。由于 limit 1
,它会找到匹配项并立即停止。不过,可能发生的情况是它没有评估 where
根据您的查询,以相同的顺序子句。 SQL 不保证 a <> 0
参与a <> 0 and b / a > c
首先得到评估。适用于您的情况,它不保证在 a 中的行与 b 连接后获得咨询锁。
关于sql - Postgres pg_try_advisory_lock 阻塞所有记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20115907/