分離レベルについて説明する

完了

PostgreSQL には 3 つのレベルのトランザクション分離があり、それによって、3 種類のコンカレンシー競合、ダーティ読み取り、反復不可能な読み取り、ファントム読み取りを防止しています。

コンカレンシー競合の種類

ダーティ リード

あるトランザクションが、別のトランザクションで編集中の更新されたバージョンのデータを読み取ると、ダーティ リードが発生します。 ただし、この更新がコミットされることはありません。

たとえば、口座の残高が 0 未満になるようなトランザクションが普通預金口座で発生したとします。 トランザクションがコミットされる前に、口座の残高がチェックされ、取引がロールバックされます。これは、預金口座の残高が 0 を下回ることが許可されていないためです。 同時に、すべての預金口座の現在の残高を示すレポートが実行されます。 ダーティ リードが許可されている場合、負の残高は、コミットされることはなくても返されます。

反復不可能な読み取り

あるトランザクションがデータを読み取り、別のトランザクションがデータを更新してから、最初のトランザクションが再びデータを読み取って新しい更新を検出した場合、反復不可能な読み取りが発生します。

たとえば、接続 A がトランザクションを開始して注文の単位あたりのコストと単位数を読み取り、コストが 10 でコストと単位数が 3 であったとします。 その後、接続 B が別のトランザクションを開始し、同じ注文を更新して単位あたりのコストを 12 に設定します。 元のクエリと同じトランザクションで、接続 A は注文の合計コストを計算します。 反復不可能な読み取りが許可されている場合、接続 A は単位あたりのコスト 10、単位数 3、合計コスト 36 を返します。これは明らかに意味をなしません。

ファントム読み取り

あるトランザクションがデータを読み取り、別のトランザクションが新しい行 (1 つまたは複数) をデータに追加してから、最初のトランザクションがデータを再度読み取って新しい更新を検出した場合、ファントム読み取りが発生します。

たとえば、接続 A がトランザクションを開始し、パリでのその日の請求書の合計数をカウントします。 パリにある全 10 店での請求書の合計数は 1,100 になりました。 その後、接続 B が別のトランザクションを開始し、パリの新しい小売店の開店日に 200 件の請求書を追加します。 接続 A のトランザクションでは、システムは店舗数をカウントし、店舗ごとの請求書数を計算しています。 このとき、接続 A は、請求書カウント クエリを実行した時点で存在していた元の 10 ではなく 11 店で、1,100 件のトランザクションを除算します。 この計算では、新しい店の請求書 200 件が、接続 A のトランザクションによる平均の計算で考慮されておらず、正しくない平均 100 が返されます。

分離レベル

Azure Database for PostgreSQL には、コミットされたものの読み取り、反復可能な読み取り、シリアル化可能という 3 つのトランザクション分離レベルがあります。 コミットされていないものの読み取りは、Azure Database for PostgreSQL では使用できません。

分離レベルがコンカレンシーの競合に与える影響:

分離レベル ダーティ リード 反復不可能な読み取り ファントム読み取り
コミットされていないものの読み取り* 可能 可能 可能
READ COMMITTED 不可能 可能 可能
REPEATABLE READ 不可能 不可能 可能
シリアル化可能 不可能 不可能 不可能

* PostgreSQL では使用できません

コミットされたものの読み取りは、Azure Database for PostgreSQL の既定の分離レベルです。 ほとんどのシナリオに最も適しているのは、コミットされたものの読み取りです。これは、良好なパフォーマンスを提供しながらダーティ リードを防止するためです。 反復不可能な読み取りとファントム読み取りを行うことができますが、これらの状況は、同じデータのクエリを同時に実行する複数の SELECT ステートメントがある場合にのみ発生できます。

反復可能な読み取りは、コミットされたものの読み取りとは異なります。なぜなら、トランザクションの 2 つの SELECT ステートメントの実行の間に、別のトランザクションが行を更新した場合でも、トランザクション内の複数の SELECT ステートメントで同じ結果が表示されるからです。 別のトランザクションが新しい行を挿入した場合、それらの行は 2 番目の SELECT ステートメントの結果には表示されません。

シリアル化可能な分離レベルは、最も高度なレベルのトランザクション分離を提供し、異なる複数のトランザクションが連続して (つまり、1 つずつ) 実行されているかのように実行されます。 シリアル化可能な分離レベルの欠点は、トランザクションが更新を実行している場合、他のトランザクションがそれをブロックする可能性があることです。 シリアル化可能なトランザクションは、ブロックしているトランザクションが完了するまで待つ必要があり、パフォーマンスに影響します。

また、シリアル化可能なトランザクションでは、シリアル化可能なトランザクションの間に他のトランザクションが変更した行を変更できません。 この形式の競合が発生した場合はエラー メッセージが返されるため、シリアル化可能なトランザクションを使用する場合は、再試行ロジックをアプリケーションに組み込むことが重要です。

トランザクション分離レベルを更新するには、トランザクション内で TRANSACTION ISOLATION LEVEL コマンドを使います。

次に例を示します。

BEGIN TRANSACTION
TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM humanresources.department
COMMIT;