[英]Put pg_try_advisory_xact_lock() in a nested subquery?
在我的Ruby on Rails 4應用程序中,我有以下查詢到Postgres 9.4數據庫:
@chosen_opportunity = Opportunity.find_by_sql(
" UPDATE \"opportunities\" s
SET opportunity_available = false
FROM (
SELECT \"opportunities\".*
FROM \"opportunities\"
WHERE ( deal_id = #{@deal.id}
AND opportunity_available = true
AND pg_try_advisory_xact_lock(id) )
LIMIT 1
FOR UPDATE
) sub
WHERE s.id = sub.id
RETURNING sub.prize_id, sub.id"
)
dba.SE上的相關答案極大地啟發了我們 。
但是在這里( Postgres pg_try_advisory_lock阻止了所有記錄 ),他們說,如果我沒記錯的話,我不應該在WHERE
子句中使用pg_try_advisory_lock()
,因為我將在被掃描的整個集中的每一行調用一次它。在where子句中進行的過濾)。
我只想讓我的查詢查找並更新第一行(使用LIMIT
隨機地),其中available = true
並將其更新為available = false
,我需要在執行此操作時鎖定該行,但無需等待新的請求來等待發布之前的鎖中的一個,因此我添加了這里建議的咨詢鎖。
我應該將pg_try_advisory_lock()
放在WHERE
子句之外嗎? 怎么做?
我更新了參考答案,並提供了更多解釋和鏈接。
在Postgres 9.5(當前為beta)中,新的“ SKIP LOCKED
是一種出色的解決方案:
讓我先簡化一下查詢中的幾件事:
UPDATE opportunities s
SET opportunity_available = false
FROM (
SELECT id
FROM opportunities
WHERE deal_id = #{@deal.id}
AND opportunity_available
AND pg_try_advisory_xact_lock(id)
LIMIT 1
FOR UPDATE
) sub
WHERE s.id = sub.id
RETURNING s.prize_id, s.id;
opportunity_available = true
簡化為opportunity_available
*
,只需id
就足夠了。 通常,這是按原樣工作的 。 以下說明。
可以肯定的是,您可以在下一個查詢級別應用pg_try_advisory_xact_lock()
之前 ,將所有謂詞用OFFSET 0
hack(較少的開銷)封裝在CTE或子查詢中:
UPDATE opportunities s
SET opportunity_available = false
FROM (
SELECT id
FROM (
SELECT id
FROM opportunities
WHERE deal_id = #{@deal.id}
AND opportunity_available
AND pg_try_advisory_xact_lock(id)
OFFSET 0
) sub1
WHERE pg_try_advisory_xact_lock(id)
LIMIT 1
FOR UPDATE
) sub2
WHERE s.id = sub.id
RETURNING s.prize_id, s.id;
但是 ,這通常要貴得多。
如果您將查詢基於涵蓋所有謂詞的索引(例如此部分索引),則不會有任何“附帶”咨詢鎖:
CREATE INDEX opportunities_deal_id ON opportunities (deal_id)
WHERE opportunity_available;
與EXPLAIN
一起檢查以驗證Postgres實際使用了索引。 這樣, pg_try_advisory_xact_lock(id)
將成為索引或位圖索引掃描的過濾條件,並且只有合格的行才開始進行測試(並鎖定),因此您可以使用簡單的表單而無需其他嵌套。 同時,您的查詢性能得到了優化。 我會做到這一點 。
即使幾個不相關的行偶爾會獲得咨詢鎖,通常也沒關系。 咨詢鎖僅與實際使用咨詢鎖的查詢有關。 還是您真的有其他並發事務也使用咨詢鎖並定位同一表的其他行? 真?
唯一有問題的情況是,如果大量無關的行都獲得了咨詢鎖,這只能在順序掃描中發生,即使在那時也不太可能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.