sql - Postgres pg_try_advisory_lock 阻塞所有记录

标签 sql postgresql locking

我在 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/

相关文章:

spring - 如何使用 Spring Boot 在集群内只执行一次计划任务?

t-sql - 分离数据库/脱机失败

mysql - 使用 IN 子句 MySQL 子查询结果返回逗号分隔值

SQL Insert Select 当select 检索多条记录时

ruby-on-rails - 如何让 postgres 在 big sur 上启动?

python - Python 的 file.write 是原子的吗?

mysql根据另一个表中的字段对列进行排序

sql - 将 SQL 文件上传到 GitHub 存储库

SQL 数据类型,最多 15 位小数的货币值

ruby-on-rails - 向 Heroku 数据库插入记录