簡體   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