ぱと隊長日誌

ブログ運用もエンジニアとしての生き方も模索中

PostgreSQLマニュアルのトランザクション分離レベル表を参照する際の注意点

はじめに

PostgreSQLマニュアル「13.2. トランザクションの分離」にはトランザクション分離レベルの表が記載されています。この表の記載は9.4以前と9.5以降で変わっており、PostgreSQLの挙動が変わったと勘違いしてしまうかもしれません。ですが、マニュアルを注意深く読み解けば挙動に違いの無いことが分かります。本エントリではこれを解説します。

トランザクション分離レベルの表があらわすもの

注目すべきは表タイトルです。

バージョン 表タイトル
9.4 表 13-1. 標準SQLトランザクション分離レベル
9.5 表13.1 トランザクション分離レベル

9.4で記載されている表は「標準SQLトランザクション分離レベル」です。「PostgreSQLトランザクション分離レベル」ではありません。「標準SQLトランザクション分離レベル」とはANSI(米国国家規格協会)で定義されたトランザクション分離レベルのことです。

9.4の「標準SQLトランザクション分離レベル」を引用します。

分離レベル ダーティリード 反復不能読み取り ファントムリード
リードアンコミッティド 可能性あり 可能性あり 可能性あり
リードコミッティド 安全 可能性あり 可能性あり
リピータブルリード 安全 安全 可能性あり
リアライザブル 安全 安全 安全

これに対し、9.5で記載されている表は「トランザクション分離レベル」です。これは標準SQLPostgreSQLで実装されているトランザクション分離レベルをまとめて記載しています。

9.5の「トランザクション分離レベル」を引用します。

分離レベル ダーティリード 反復不能読み取り ファントムリード 直列化異常
リードアンコミッティド 許容されるが、PostgreSQLでは発生しない 可能性あり 可能性あり 可能性あり
リードコミッティド 安全 可能性あり 可能性あり 可能性あり
リピータブルリード 安全 安全 許容されるが、PostgreSQLでは発生しない 可能性あり
リアライザブル 安全 安全 安全 安全
13.2. トランザクションの分離

この表には「許容されるが、PostgreSQLでは発生しない」という記載があります。これは標準SQLがそれぞれの分離レベルで提供しなくてはならない最小の保護のみを示しており、PostgreSQLは標準SQLより厳密な動作で実装しているということです。つまり先ほどの記載は「(標準SQLでは)許容されるが、PostgreSQL(の実装)では発生しない」といえます。

このことはマニュアルにも記載されています。

より厳密な動作をすることは標準SQLでも許されています。 つまり、この4つの分離レベルでは、発生してはならない事象のみが定義され、発生しなければならない事象は定義されていません。

13.2. トランザクションの分離

この結果として、PostgreSQLでは4つの標準SQLトランザクション分離レベルを全て要求することができますが、PostgreSQLのリードアンコミッティドモードは標準SQLのリードコミッティドに相当する挙動を示すため、実質的に3つのトランザクション分離レベルしか存在しないことになります。また、リピータブルリードモードではファントムリードが発生せず、標準SQLが求めるよりも厳密な動作で実装されています。

直列化異常とはなにか?

直列化異常について、マニュアルでは以下の説明をしています。

直列化異常
複数のトランザクションを正常にコミットした結果が、それらのトランザクションを1つずつあらゆる可能な順序で実行する場合とは一貫性がない。

13.2. トランザクションの分離

直列化異常の具体例としてマニュアルには2つ記載されています。

  1. 「13.2.2. リピータブルリード分離レベル」制御レコード
  2. 「13.2.3. シリアライザブル分離レベル」mytabテーブル

制御レコードの例はマニュアルの記載だとわかりにくいため、以下のエントリも併せて参照ください。
PostgreSQLマニュアルの「リピータブルリード分離レベル」における「制御レコード」とはなにか? - ぱと隊長日誌

トランザクション分離レベルの表には9.5から「直列化異常」が追加されています。ですが、9.4以前でもこの事象は発生します。これは先に挙げた直列化異常の例が9.4のマニュアルにも記載されていることからわかります。

なお、同時実行トランザクションを一度に一つずつ実行することについて、日本語版マニュアルの9.5以前で「並列」と記載していた箇所が9.6以降は「直列」となっています。これは英語版マニュアルで以前から"serial"と記載されており、「直列」との記載が正しいです。

しかし、このビューは常にいくつかの同じレベルの同時実行トランザクション並列(一度に一つずつの)実行で一貫性を持つ必要はありません。
※9.5より引用

13.2. トランザクションの分離

しかし、このビューは常にいくつかの同じレベルの同時実行トランザクション直列(一度に一つずつの)実行と一貫性を持つとは限りません。
※9.6より引用

13.2. トランザクションの分離

However, this view will not necessarily always be consistent with some serial (one at a time) execution of concurrent transactions of the same level.
※9.6英語版より引用。なお、9.5英語版でも同じ記載となっている。

PostgreSQL: Documentation: 9.6: Transaction Isolation