★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

12.4. アプリケーションレベルでのデータの一貫性チェック

PostgreSQLでのデータ読み取りはデータをロックしないので、トランザクションの隔離レベルに関係なく、あるトランザクションで読み込まれたデータは、同時に実行されているもう一方のトランザクションによって書き変えられる可能性があります。 言い換えると、SELECT で得た行は、その行が返ってきた時 (現在の問い合わせが開始された後のある時点)に最新であるということを意味していません。 このトランザクションが開始した後であっても別のトランザクションがコミットしたことで、見ている行は更新、もしくは削除されてしまっている可能性があります。 "今"その行が有効であったとしても、現在実行中のトランザクションがコミットまたはロールバックで完了する前に(別のトランザクションによって)変更されたり、削除される可能性があります。

各々のトランザクションは特定のデータベースの内容のスナップショットを参照していて、同時に実行されているトランザクションが異なったスナップショットを参照している可能性が十分にありうると考えることもできます。 従って、どちらにしても"今"という概念は少々おかしな定義となります。 これは通常、それぞれのクライアントアプリケーションがお互いに隔離されている場合は大きな問題ではありませんが、クライアント同士がデータベースの外で何かのチャンネルを使用して通信できる場合は大きな問題となります。

現在有効な行を確実なものとし、同時に起こり得る更新を避けるためには、SELECT FOR UPDATE文や、適切なLOCK TABLE文を使用する必要があります。 (SELECT FOR UPDATE文は返ってきた行のみを同時に起こる更新からロックし、LOCK TABLEはテーブル全体をロックします。) これはPostgreSQLに他の環境からアプリケーションを移植するときに考慮されなければなりません。 (PostgreSQLバージョン6.5以前では、読み取りロックが使用されていました。 ですので、バージョン6.5以前のPostgreSQLからアップグレードする時も、上の考慮は関係してきます。)

MVCCにおいてはグローバル有効性チェックに特別な考慮を払わなければなりません。 例えば銀行のアプリケーションで、テーブルにある全ての貸方の合計が、別のテーブルにある借方の合計と同じであることをチェックする必要があるとします。 そして、この両方のテーブルは常に更新されています。 2つの連続するSELECT SUM(...)コマンドの結果を比べると、2番目の問い合わせは、おそらく最初の問い合わせによってカウントされなかったトランザクションの結果を含んでいるため、リードコミッティドモードでは信頼のおける処理を実行できないことが分かります。 1つのシリアライザブルトランザクションで2つの合計を出力すると、シリアライザブルトランザクションが開始される前にコミットされたトランザクション結果の正確な状況を得ることができます。 しかし、その結果がもたらされた時点でもなお妥当であるかどうかは、実際には疑わしいかもしれません。 整合性チェックを行なう前にシリアライザブルトランザクション自身が変更を行なった場合、そのチェックの有効性はさらに疑わしくなります。 これにより、トランザクション開始後に行なわれる変更の全てだけでなく、何か別のものが含まれるためです。 このような場合、注意深い人であれば、現状を確実に把握するためにチェックに必要な全てのテーブルをロックするでしょう。 SHARE モード(もしくはそれ以上)のロックにより、現在のトランザクションでの変更を除き、ロックされたテーブルにコミットされていない変更が存在しないことが保証されます。

また、明示的なロック処理を使用して、同時に変更が実行されるのを防ごうとする場合、リードコミッティドモードを使用すべきであることに注意してください。 もしくは、シリアライザブルモードを使用する場合は、問い合わせを実行する前にロックを獲得するよう留意してください。 シリアライザブルトランザクションにおいて獲得されたロックは、テーブルに変更をかける他のトランザクションが現在実行されていないことを保証します。 しかし、トランザクションが参照しているスナップショットが、ロックの獲得より前に取得されたものであれば、そのスナップショットは現時点においてコミットされている変更より前のテーブルのものである可能性があります。 シリアライザブルトランザクションのスナップショットは、実際にはその最初の問い合わせもしくはデータ変更コマンド(SELECTINSERTUPDATE、または DELETE)が開始された時点で取得されます。 従って、スナップショットを取得する前に、明示的にロックを獲得することは可能です。