すべてのプロダクト
Search
ドキュメントセンター

PolarDB:アプリケーションレベルでのデータ整合性チェック

最終更新日:Jun 03, 2024

データのビューはステートメントごとにシフトしているため、Read Committedトランザクションを使用してデータの整合性に関するビジネスルールを適用することは非常に困難です。また、書き込み競合が発生した場合、単一のステートメントでもステートメントのスナップショットに制限されない場合があります。

Repeatable Readトランザクションは、その実行全体を通してデータを安定して見ることができますが、MVCCsnapshotsを使用してデータの整合性チェックを行うことには、読み取り /書き込みの競合と呼ばれる問題があります。 一方のトランザクションがデータを書き込み、同時実行トランザクションが同じデータを読み取ろうとすると (書き込みの前または後に) 、もう一方のトランザクションの作業を確認できません。 リーダーは、どちらが最初に開始されたか、どちらが最初にコミットされたかに関係なく、最初に実行したように見えます。 それがそうであれば、問題はないが、リーダが同時トランザクションによって読み取られるデータも書き込む場合、前述のトランザクションのいずれかの前に実行されたように見えるトランザクションが存在する。 最後に実行されたように見えるトランザクションが実際に最初にコミットする場合、トランザクションの実行順序のグラフにサイクルが現れることは非常に容易である。 このようなサイクルが表示されると、整合性チェックは何らかの助けがなければ正しく機能しません。

シリアル化可能なトランザクションは、読み取り /書き込みの競合の危険なパターンに対する非ブロック監視を追加する繰り返し可能な読み取りトランザクションです。 実行の見かけの順序でサイクルを引き起こす可能性のあるパターンが検出されると、関与するトランザクションの1つがロールバックされてサイクルを中断します。

シリアル化可能なトランザクションとの整合性の実施

シリアル化可能なトランザクション分離レベルが、データの一貫性のあるビューを必要とするすべての書き込みおよびすべての読み取りに使用される場合、一貫性を確保するために他の労力は必要ありません。 シリアル化可能なトランザクションを使用して一貫性を確保するように記述されている他の環境のソフトウェアは、PolarDB PostgreSQLでこの点で「機能する」必要があります。

この技術を使用する場合、アプリケーションソフトウェアが、シリアル化の失敗でロールバックされたトランザクションを自動的に再試行するフレームワークを通過する場合、アプリケーションプログラマに不必要な負担が生じることを回避する。 default_transaction_isolationserializableに設定することをお勧めします。 また、トリガにおけるトランザクション分離レベルのチェックを介して、不注意で、または完全性チェックを覆すために、他のトランザクション分離レベルが使用されないことを保証するために、何らかの措置を講じることも賢明であろう。

警告

シリアル化可能トランザクションを使用したこのレベルの整合性保護は、まだホットスタンバイモードには拡張されません。 そのため、ホットスタンバイを使用している人は、プライマリでRepeatable Readと明示的なロックを使用したい場合があります。

明示的ブロッキングロックによる整合性の実施

シリアル化できない書き込みが可能な場合、行の現在の有効性を確保し、同時更新から保護するには、SELECT FOR UPDATESELECT FOR SHARE、または適切なLOCK TABLEステートメントを使用する必要があります。 (SELECT FOR UPDATEおよびSELECT FOR SHAREは、返された行のみを同時更新に対してロックし、lock TABLEはテーブル全体をロックします。) これは、他の環境からアプリケーションをPostgreSQLに移植するときに考慮する必要があります。

また、他の環境から変換する場合には、SELECT FOR UPDATEは、同時トランザクションが選択された行を更新または削除しないことを保証しないという事実が注目されます。 PolarDB PostgreSQLでこれを行うには、値を変更する必要がない場合でも、実際に行を更新する必要があります。SELECT FOR UPDATEは、他のトランザクションが同じロックを取得したり、ロックされた行に影響を与えるUPDATEまたはDELETEを実行したりするのを一時的にブロックしますが、このロックを保持しているトランザクションがコミットまたはロールバックすると、ブロックされたトランザクションは、ロックを保持している間に行の実際のUPDATEが実行されない限り競合操作を続行します。

グローバル有効性チェックには、シリアル化できないMVCCでの特別な検討が必要です。 例えば、銀行業務アプリケーションは、両方のテーブルがアクティブに更新されているときに、1つのテーブルのすべてのクレジットの合計が別のテーブルのデビットの合計に等しいことをチェックしたい場合があります。 2つの連続するSELECT sum(...) コマンドの結果を比較することは、2番目のクエリが最初にカウントされていないトランザクションの結果を含む可能性が高いため、Read Committedモードでは確実に機能しません。 単一の繰り返し可能な読み取りトランザクションで2つの合計を実行すると、繰り返し可能な読み取りトランザクションが開始する前にコミットされたトランザクションの効果のみが正確に把握されますが、回答が配信されるまでにまだ関連しているかどうかを正当に疑問に思う場合があります。 一貫性チェックを行おうとする前に反復可能な読み取りトランザクション自体がいくつかの変更を適用した場合、チェックの有用性はさらに議論の余地があります。 そのような場合、注意深い人は、現在の現実の議論の余地のない絵を得るために、チェックに必要なすべてのテーブルをロックしたいと思うかもしれません。 SHAREモード (またはそれ以上) のロックは、現在のトランザクションの変更以外に、ロックされたテーブルにコミットされていない変更がないことを保証します。

また、同時変更を防ぐために明示的なロックに依存している場合は、Read Committedモードを使用するか、Repeatable Readモードでクエリを実行する前にロックを取得するように注意してください。 反復可能な読み取りトランザクションによって取得されるロックは、テーブルを変更する他のトランザクションがまだ実行されていないことを保証しますが、トランザクションによって見られるスナップショットがロックを取得する前のものである場合、テーブル内のいくつかの現在コミットされた変更よりも前のものである可能性があります。 繰り返し可能な読み取りトランザクションのスナップショットは、最初のクエリまたはデータ変更コマンド (SELECTINSERTUPDATEDELETE) の開始時に実際に凍結されるため、スナップショットが凍結される前にロックを明示的に取得できます。