Postgres、MVCC、およびロック


8

次のような一連のSQLステートメントがあります。

BEGIN;
SELECT counter FROM table WHERE id=X FOR UPDATE;
REALLY COMPLEX QUERY;
UPDATE table SET counter=Y WHERE id=X;
END;

値を再計算している間、カウンターが読み取られないようにしたいのですが、Postgresのドキュメントによると、「行レベルのロックはデータのクエリに影響を与えません。それらは同じ行への書き込みのみをブロックします。」

質問:

  1. 読み取りを妨げない場合の「排他的」行ロックの意味は何ですか?他のトランザクションが共有ロックを取得するのを防ぐだけですか?
  2. SELECT ... FOR SHAREを使用して行を読み取ると、「排他的」ロックと同じ影響がありますか?
  3. テーブル/スキーマ/データベースのMVCCをオフにして、インプレース書き込みを許可することは可能ですか?

回答:


5

1)他のセッションは、トランザクションがコミットしない限り、「BEGIN」ステートメントの前と同じようにトランザクションによって変更されたデータを読み取ります。トランザクションがコミットされるとすぐに、カウンターの新しい値が読み取られます。重要なのは、他の人が待つ必要がなく、常に一貫したデータベースが表示されることです。

2)、3)に「ACCESS EXCLUSIVE」で試してみませんか?(http://www.postgresql.org/docs/current/static/explicit-locking.htmlを参照してください

編集:「ACCESS EXCLUSIVE」ロックでテーブル全体をロックしたくない場合は、「アドバイザリロック」を使用することもできます(上記のリンクのセクション13.3.4を参照)。


1

ブロックする読み取りが、同じデータを異なるデータで同時に実行する場合は、returning句を指定したUPDATEステートメントを使用します。

UPDATEステートメントのドキュメントを確認してください。排他的な行ロックのポイントについての質問に答えるには、同時更新によるデータの不整合を防止する必要があります。読者は常にデータベースの一貫したビューを取得します。


1

指定したコードサンプルでは、​​そのトランザクションがコミットするまで、その行のすべての読み取りで古い値が表示されます。

1)同じサンプル値で、2回同時に実行されるコードサンプルを考えますX。インスタンスAが実行select ... for updateされると、コミットするまでその行がロックされます。同じことを行うインスタンスBは、同じ方法でロックを取得しようとするとブロックされます。Aがコミットしたときのみ、Bは続行できます。その後、Bは最終更新で値Aを残します。

クエリが読み取るYselect ... for update、または「複雑な」部分での別の読み取りに依存する場合、これはそれらがシリアルに実行された場合と同じ結果になります-結果の1つが発生する競合状態を取得しません破棄されました。

Yが真ん中の複雑なクエリの純粋な結果である場合、select ... for update両方を使用せずに並列に実行すると、同じ更新が行われます。

2)for shareその行の他の選択を続行できるようにしますが、それが完了するまで他の何かを試みselect ... for updateたりupdate ...ブロックしたりします。サンプルコードが2回同時に実行された場合、updateステートメントに到達するとデッドロックし、そのうちの1つが中止されます。

3)いいえ。リーダーが半分更新されたフィールドを読み取る可能性があるため、これを行うことは危険です。(または、読み取りの開始後に更新された残りのフィールドを読み取ります。)また、一貫性が失われ、トランザクションの開始後に更新された値がリーダーに表示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.