マルチバージョン読み取りの一貫性について
データの読み書きを相互排他しないようにサポートするため、OceanBaseデータベースは複数のバージョンのデータを格納します。マルチバージョンデータのセマンティクスを処理するためには、マルチバージョンの一貫性を維持する必要があります。OceanBaseデータベースのマルチバージョン一貫性は、読み取りバージョンとデータバージョンによって保証されます。バージョン番号を読み取り、読み取ったバージョン番号より小さいすべてのコミット済みデータを返すことで、マルチバージョン一貫性が定義されます。
したがって、以下の点に注意する必要があります:
コミットされていないトランザクション:自身のトランザクション以外の未コミットデータを読み取ることはできません。そうでない場合、対応するトランザクションがロールバックされたときにダーティリード(dirty read)が発生します。
トランザクション一貫性のスナップショット:読み取ったバージョン番号より小さいすべてのコミット済みデータを読み取ることで、ユーザーが理解可能な一貫性のポイントを保証します。そうでない場合、フラクチャードリード(fractured read)が発生します。
読み書きの非相互排他:未コミットトランザクションとトランザクション一貫性のポイントを満たす前提の下でも、読み書きの非相互排他を保証する必要があります。
マルチバージョン読み取りの一貫性の使用
マルチバージョン読み取りの一貫性は、データベース内部で広く使用されており、並行制御を実現する鍵の一つです:
弱い一貫性の読み取り:OceanBaseデータベースの弱い一貫性の読み取りは、依然としてトランザクションの一貫性のスナップショットを提供し、未コミットトランザクションや半分のトランザクションを返すことはありません。
強い一貫性の読み取り:OceanBaseデータベースの強い一貫性の読み取りは、トランザクションレベルのバージョン番号読み取りとステートメントレベルのバージョン番号読み取りの2種類に分かれており、それぞれスナップショット読み取りとコミット済み読み取りの2つの分離レベルで使用されます。トランザクションの一貫性のポイントを返す機能が必要です。
読み取り専用トランザクション:OceanBaseデータベースの読み取り専用ステートメントも、強い一貫性の読み取りと同じ機能を提供する必要があり、トランザクションの一貫性のポイントを返す機能が必要です。
バックアップ復元ポイント:OceanBaseデータベースは、トランザクションの一貫性のスナップショットまでバックアップできる機能を提供する必要があります。これにより、余分な未コミットトランザクションをバックアップしたり、バックアップが必要なトランザクションをバックアップしなかったりするのを防ぎます。
ユーザーがマルチバージョンを使用する過程は、以下の図のようになります:

上図の左側に示すように、データAには100バージョンのコミット済みデータaが含まれており、対応するトランザクションはトランザクション10です。また、コミット済みデータbが含まれており、対応するトランザクションはトランザクション7です。データBには、未決定バージョンのデータjと対応するトランザクション12、およびコミット済みデータbが含まれており、対応するトランザクションはトランザクション10です。データCには、未決定バージョンのデータxと対応するトランザクション15、およびコミット済みデータyが含まれており、対応するトランザクションはトランザクション10です。
マルチバージョン読み取りの一貫性の実現
トランザクションテーブル

トランザクションテーブルはメモリテーブルであり、そのレプリカ内で実行中のトランザクションの集合を表します。トランザクションは実行過程で異なる状態に応じて、対応するデータを読み取るかどうかを判断します。データの状態にはコミット(COMMIT)、実行中(RUNNING)、ロールバック(ABORT)が含まれます。実行中(RUNNING)のトランザクションには ローカルコミットバージョン番号(local commit version、すなわち prepare version)が存在する場合があります。コミット済みのトランザクションには グローバルコミットバージョン番号(global commit version、すなわち commit version)が存在します。ここで グローバルコミットバージョン番号 がトランザクションの最終バージョンを表し、一貫性ポイントを決定する要因となります。
上図右側に示すように、トランザクション6はロールバック状態にあります。トランザクション7はコミット状態で、グローバルコミットバージョン番号 は80です。トランザクション12は実行中で、ローカルコミットバージョン番号 は存在しません。トランザクション15は実行中で、ローカルコミットバージョン番号 は130です。
読み取りリクエスト処理
読み取り時には、読み取りバージョン番号を使用して対応するデータを読み取ります。
次に分けて分析します。コミットまたはロールバックされたトランザクションを読み取る場合、グローバルコミットタイムスタンプ と状態を比較することで、対応するデータを読み取る必要があるかどうかを簡単に推測できます。下図のように、読み取りリクエストr1は90を読み取りバージョン番号として読み取りを行い、スナップショット読み取りのポリシーに基づき、バージョン番号80、データbのデータを読み取ります。
RUNNING状態のトランザクションを読み取る場合、そのデータを安全にスキップできます。下図のように、読み取りリクエストr2は130を読み取りバージョン番号として読み取りを行い、2フェーズコミットに入っていないトランザクション12を安全にスキップして、バージョン番号100、データbのデータを読み取ります。
PREPARE状態のトランザクションを読み取る場合、トランザクションがコミットされるかどうかは不確定なため、その行のトランザクションを待機します。下図のように、読み取りリクエストr3は140を読み取りバージョン番号として読み取りを行い、2フェーズコミット状態で ローカルコミットタイムスタンプ が130のトランザクションを待機し、最終的に グローバルコミットタイムスタンプ と読み取りタイムスタンプ140の関係を決定します。