[英]Postgres pg_try_advisory_lock blocks all records
I'm using pg_try_advisory_lock()
in Postgres. 我在Postgres中使用
pg_try_advisory_lock()
。
Next two queries lock more than one records in table1
: 接下来的两个查询会锁定
table1
多个记录:
1) 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;
but 但
SELECT a.id
FROM table1 a
JOIN table2 b ON a.table1_id = b.id
WHERE table2.id = 1
returns one record. 返回一条记录。
2) 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;
But I need pg_try_advisory_lock()
to lock only one record. 但我需要
pg_try_advisory_lock()
来只锁定一条记录。
What's wrong? 怎么了?
UPD UPD
But the strange thing is that when I run the following query 但奇怪的是,当我运行以下查询时
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 locks only one row. Postgres只锁定一行。 So, Postgres scans the very first row then stops?
那么,Postgres扫描第一行然后停止? I don't get it: it should scan all rows then limit the results to one row, or not?
我不明白:它应扫描所有行然后将结果限制为一行,或不?
You're calling pg_try_advisory_lock() once per row in the entire set that gets scanned (as part of the filtering that occurs in the where
clause), whereas you only want it called once per row in table1 returned by the query. 您在扫描的整个集合中的每一行调用pg_try_advisory_lock()一次(作为
where
子句中发生的过滤的一部分),而您只希望在查询返回的table1中每行调用一次。
You could try using a subquery or a CTE instead: 您可以尝试使用子查询或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);
But don't rely on that to necessarily work as expected either: Postgres should be tempted to rewrite it the way your initial query was. 但是不要依赖于它必然按预期工作:Postgres应该试图按照初始查询的方式重写它。
Another possibility is this, since the select
part of a statement is evaluated very late in the query: 另一种可能性是,因为语句的
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;
The real issue in practice is that pg_try_advisory_lock()
is something you'd normally find in app land or in a function, rather than in a query like you're doing. 实际中的真正问题是
pg_try_advisory_lock()
是你通常在app land或函数中找到的东西,而不是你正在做的查询。 Speaking of which, depending on what you're doing, are you sure you shouldn't be using select … for update
? 说到这些,取决于你正在做什么,你确定你不应该使用
select … for update
吗?
Regarding your update: 关于你的更新:
postgres scans the very first row then stops?
postgres扫描第一行然后停止?
Yes. 是。 Due to the
limit 1
, it's going to find a match and immediately stop. 由于
limit 1
,它将找到匹配并立即停止。 What is probably happening, though, is that it's not evaluating the where
clause in the same order depending on your queries. 但是,可能发生的是,它不会根据您的查询以相同的顺序评估
where
子句。 SQL offers no guarantee that the a <> 0
part in a <> 0 and b / a > c
gets evaluated first. SQL不保证首先评估
a <> 0 and b / a > c
中的a <> 0
部分。 Applied to your case, it offers no guarantee that the advisory lock is obtained after the row from a is joined with b. 适用于您的情况,它不保证在a与a连接的行之后获得咨询锁定。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.