Postgresql

SELECT FOR UPDATE 如何處理 PostgreSQL 中的視圖?

  • October 25, 2017

為了從 PostgreSQL 中檢索域模型數據,我有時會選擇視圖而不是表。我這樣做是為了在一個查詢中返回盡可能多的資訊,而不是觸發多個查詢來解決所有關係依賴項。這主要是因為表之間存在一對一的關係,或者它們是查找表,我只需要某些列等。為了防止某些競爭條件,我使用的一種策略是SELECT ... FOR SHARE/UPDATE查詢。我想知道當我們開始對視圖使用它們時它們的行為如何。


假設我們有兩個表AB,每個表都有一列ID。現在,假設我們有一個視圖AB,它是這兩個表之間的連接操作。假設這是一個笛卡爾連接:

SELECT
   "A"."ID" AS "AID",
   "B"."ID" AS "BID"
FROM "A"
CROSS JOIN "B"

如果我們在以下情況下SELECT FOR UPDATE針對AB哪些表的哪些行會被鎖定?

  • SELECT * FROM "AB" WHERE "AB"."AID" = :ID
  • SELECT * FROM "AB" WHERE "AB"."BID" = :ID
  • SELECT * FROM "AB" WHERE "AB"."AID" = :ID1 AND "AB"."BID" = :ID2

簡短的回答

在三種情況下,以下行將被鎖定以進行更新:

  • 表“A”中具有“ID”=:ID 的行和表“B”中的所有行
  • 表“B”中具有“ID”=:ID 的行和表“A”中的所有行
  • 表“A”中具有“ID”= :ID1 的行和表“B”中具有“ID”= :ID2 的行

閱讀文件中的此聲明後,結果與預期的一樣

如果鎖定子句應用於視圖或子查詢,它會影響視圖或子查詢中使用的所有表。

如何測試類似的案例

安裝擴展pgrowlocks。.

create extension if not exists pgrowlocks;

執行兩個 psql 實例。在第一個中啟動事務並執行查詢。

psql #1:

begin;

select *
from "AB"
where "AID" = 3 and "BID" = 103
for update;

您可以在 psql 的另一個實例中看到鎖定的行。

psql #2:

select * from pgrowlocks('"B"');

locked_row | locker | multi |  xids   |     modes      |  pids
------------+--------+-------+---------+----------------+--------
(0,4)      |  88577 | f     | {88577} | {"For Update"} | {8068}
(1 row) 

不要忘記在最後關閉事務(在下一次測試之前)。

psql #1:

rollback;

上述結果的第一列是ctid。您可以使用查詢選擇原始行:

select *
from "B"
where ctid = '(0,4)';

引用自:https://dba.stackexchange.com/questions/189240