简体   繁体   English

Postgres pg_try_advisory_lock会阻止所有记录

[英]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.

相关问题 将pg_try_advisory_xact_lock()放在嵌套子查询中? - Put pg_try_advisory_xact_lock() in a nested subquery? 在SELECT中嵌入pg_advisory_lock与显式使用另一个语句有什么好处? - What is the benefit of embedding pg_advisory_lock inside SELECT vs explicitly using another statement? SQL Server:锁定由select语句返回的所有记录 - Sql Server: Lock all records returned by select statement Codewars Postgres挑战pg :: syntaxerror - Codewars postgres challenge pg::syntaxerror 如何更改存储在 Postgres 中的所有记录的 JSON 对象中的键名 - How to change the name of a key in a JSON object stored in Postgres for all records 使用Postgres从多个模式中选择(检索)所有记录 - Select (retrieve) all records from multiple schemas using Postgres Rails + Postgres查询满足具有唯一关联ID的条件的所有记录 - Rails + Postgres query for all records that meet a criteria with a unique association ID 正则表达式:Postgres SQL查询返回表中所有可用的记录 - Regular expression: Postgres SQL query is returning all records available in the table 具有限制的 Postgres 查询选择具有相似标识符的所有记录 - Postgres query with limit that selects all records with similar identifier Postgres,更新和锁定订单 - Postgres, update and lock ordering
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM