web-dev-qa-db-ja.com

SELECT FOR UPDATEはPostgreSQLのビューでどのように動作しますか?

PostgreSQLからドメインモデルデータを取得するために、テーブルではなくビューを選択する場合があります。これを行うのは、複数のクエリを実行してすべてのリレーショナル依存関係を解決するのではなく、1つのクエリでできるだけ多くの情報を返すことができるようにするためです。これは主に、テーブル間に1対1の関係があるか、テーブルがルックアップテーブルであり、特定の列が必要なためなどです。特定の競合状態を防ぐために、私が使用している戦略の1つはSELECT ... FOR SHARE/UPDATEクエリ。これらをビューに対して使用し始めたとき、これらがどのように動作するのか疑問に思っています。


2つのテーブルABがあり、それぞれに列IDがあるとします。ここで、これら2つのテーブル間の結合操作であるビュー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
2
e_i_pi

短い答え

次の行は、3つのケースで更新のためにロックされます。

  • テーブル「A」の「ID」=:IDの行とテーブル「B」のすべての行
  • テーブル「B」の「ID」=:IDの行とテーブル「A」のすべての行
  • テーブル "A"の "ID" =:ID1の行とテーブル "B"の "ID" =:ID2の行

結果は、このステートメントを ドキュメント: で読んだ後に期待できるとおりです。

ロック句がビューまたはサブクエリに適用される場合、それはビューまたはサブクエリで使用されるすべてのテーブルに影響します。

同様のケースをテストする方法

拡張機能 pgrowlocks。 をインストールします。

create extension if not exists pgrowlocks;

Psqlの2つのインスタンスを実行します。最初にトランザクションを開始し、クエリを実行します。

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)';
3
klin