繁体   English   中英

Postgres pg_try_advisory_lock会阻止所有记录

[英]Postgres pg_try_advisory_lock blocks all records

我在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()是你通常在app land或函数中找到的东西,而不是你正在做的查询。 说到这些,取决于你正在做什么,你确定你不应该使用select … for update吗?


关于你的更新:

postgres扫描第一行然后停止?

是。 由于limit 1 ,它将找到匹配并立即停止。 但是,可能发生的是,它不会根据您的查询以相同的顺序评估where子句。 SQL不保证首先评估a <> 0 and b / a > c中的a <> 0部分。 适用于您的情况,它不保证在a与a连接的行之后获得咨询锁定。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM