簡體   English   中英

將pg_try_advisory_xact_lock()放在嵌套子查詢中?

[英]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;
  • 所有的雙引號都帶有合法的小寫字母名稱。
  • 由於possible_available是一個布爾列,因此您可以將opportation_available 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM