4つの分離レベル
Read UncommittedからSerializableまで、それぞれで許可される動作を学びます。
「4つの分離レベル」はCoddyKit上の無料Coding Interview Prepレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはCoding Interview Prep学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Coding Interview Prepコースには全4レッスンが含まれています。
質問の裏にある問い
面接官が「4つの分離レベルを挙げてください」と尋ねるとき、本当に確認したいのは、トレードオフを説明できるかどうかです。分離性が強いほど異常は少なくなりますが、同時実行性は低下します。
SQL標準で定義されている4つのレベルは、弱いものから強いものの順に次のとおりです。
- READ UNCOMMITTED
- READ COMMITTED
- REPEATABLE READ
- SERIALIZABLE
各レベルでは、特定の読み取り異常が許可または禁止されます。このレッスンでは各レベルを扱い、次のレッスンでは異常について詳しく扱います。
分離レベルの設定
分離レベルは、トランザクション単位またはセッション単位で設定します。構文はデータベースエンジンが異なってもほぼ同じです。
設定しない場合は、各データベースにデフォルトの分離レベルがあります。デフォルトを知っているかは面接でよく問われるため、最後に扱います。
-- Per transaction (standard SQL)
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- ... statements ...
COMMIT;
-- Per session
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;レベル1: READ UNCOMMITTED
READ UNCOMMITTEDは最も弱い分離レベルです。あるトランザクションが変更したものの、まだコミットしていない行を、別のトランザクションが読み取れます。これをダーティリードと呼びます。
その別のトランザクションがロールバックすると、正式には存在しなかったデータを読み取ったことになります。正確性が求められる処理では危険です。
注: PostgresではREAD UNCOMMITTEDがREAD COMMITTEDと同じように扱われるため、実際にダーティリードが発生することはありません。SQL ServerとMySQLではREAD UNCOMMITTEDがそのまま適用されます。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN;
-- may see another transaction's uncommitted (dirty) rows
SELECT balance FROM accounts WHERE id = 1;
COMMIT;レベル2: READ COMMITTED
READ COMMITTEDでは、コミット済みのデータだけを読み取ることが保証されます。ダーティリードは発生しません。
ただし、各SQL文は最新のコミット済みスナップショットを参照します。1つのトランザクション内で同じクエリを2回実行すると、その間に別のトランザクションがコミットされ、結果が変わる可能性があります。この異常を非反復読み取りと呼びます。
これはPostgres、Oracle、SQL Serverのデフォルトであり、多くのアプリケーションにとって妥当なバランスです。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- returns 500
-- another transaction commits an update to id = 1
SELECT balance FROM accounts WHERE id = 1; -- may now return 700
COMMIT;レベル3: REPEATABLE READ
REPEATABLE READでは、同じトランザクション内で同じ行を2回読み取った場合、両方で同じ値が返されることが保証されます。トランザクション開始時に一貫したスナップショットを取得します。
ダーティリードと非反復読み取りを防ぎます。ただし、SQL標準ではファントムリードが引き続き許可されます。これは、WHERE句に一致する新しい行が再実行時に現れる現象です。
重要: これはMySQL/InnoDBのデフォルトです。また、InnoDBの実装では、ネクストキーロックによってほとんどのファントムリードも防がれます。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- 500
-- another transaction commits a change to id = 1
SELECT balance FROM accounts WHERE id = 1; -- still 500 in this txn
COMMIT;レベル4: SERIALIZABLE
SERIALIZABLEは最も厳しい分離レベルです。データベースは、トランザクションを同時実行した結果が、何らかの直列な順序で1つずつ実行した結果と同じになることを保証します。
ダーティリード、非反復読み取り、ファントムリードを防ぎます。その代償として、より多くのロックが必要になります。また、Postgresでは直列化失敗によってトランザクションが中止されることがあり、再試行が必要です。
面接での表現:「SERIALIZABLEは、同時実行性の低下と再試行の可能性を代償に、すべてのトランザクションが単独で実行されたかのような状態を実現します」
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT SUM(balance) FROM accounts;
INSERT INTO audit (total) VALUES (...);
COMMIT; -- may raise a serialization_failure you retry異常の対応表
最も役立つ暗記事項は、各レベルでどの異常が許可されるかです。「Yes」はその異常が発生する可能性があることを示します。
- READ UNCOMMITTED: ダーティ=Yes、非反復=Yes、ファントム=Yes
- READ COMMITTED: ダーティ=No、非反復=Yes、ファントム=Yes
- REPEATABLE READ: ダーティ=No、非反復=No、ファントム=Yes(標準上)
- SERIALIZABLE: ダーティ=No、非反復=No、ファントム=No
レベルが1段階上がるごとに、さらに1つの異常が禁止されます。この段階的な関係が答えのすべてです。
標準と実際の実装の違い
上級者向けに重要な区別があります。SQL標準は、どのように防ぐかではなく、どの異常を必ず防ぐ必要があるかによってレベルを定義しています。実際のエンジンでは、それ以上の異常も防ぐことがよくあります。
- PostgresのREPEATABLE READはスナップショット分離を使用し、ファントムリードも防ぎます。ただし、ライトスキューは依然として発生する可能性があります。
- MySQL/InnoDBのREPEATABLE READは、ネクストキーロックによってファントムリードを防ぎます。
- PostgresのSERIALIZABLEはSSI(Serializable Snapshot Isolation)を使用し、重いロックではなく、競合時にトランザクションを中止します。
この点に触れると、標準は最低限の基準であり、実際の動作そのものを完全に規定するものではないと理解していることを示せます。
データベースエンジンごとのデフォルトレベル
デフォルトは頻繁に質問されます。次の内容は覚えておきましょう。
- PostgreSQL: READ COMMITTED
- Oracle: READ COMMITTED(ダーティリードは決して発生しません)
- SQL Server: READ COMMITTED
- MySQL(InnoDB): REPEATABLE READ
MySQLだけが異なる点は、面接でよく問われるひっかけです。「デフォルトの分離レベルは何ですか」と聞かれたら、まずデータベースエンジンを確認してください。
実際の運用でのレベル選択
どのように決めればよいのでしょうか。リスクとスループットのバランスとして考えます。
- 一般的なOLTPにはREAD COMMITTEDを使用します。高速で、ダーティリードを防げます。
- 同じデータをトランザクション内で何度も読み取り、その内容を安定させる必要がある場合(レポートや複数ステップの計算など)はREPEATABLE READを使用します。
- いかなる異常も許容できない、正確性が最優先の処理にはSERIALIZABLEを使用し、中止に備えて再試行のロジックを設計します。
本番環境でREAD UNCOMMITTEDを使用することは、ほとんどありません。
よくある追加質問
分離レベルを列挙した後、面接官はすぐに追加質問をしてきます。簡潔に答えられるようにしておきましょう。
- 「ダーティリードを防ぎながら、非反復読み取りを許可するレベルはどれですか」READ COMMITTEDです。
- 「標準上、REPEATABLE READが引き続き許可する唯一の異常は何ですか」ファントムリードです。
- 「なぜ常にSERIALIZABLEを使わないのですか」同時実行性が低下し、直列化失敗によってトランザクションの再試行が必要になることがあるためです。
- 「より高いレベルほどコストがかかりますか」はい。ロックのコスト、または中止と再試行のオーバーヘッドが増加します。
これらに即答できれば、分離レベルの段階を暗記しただけでなく、身に付けていることを示せます。
理解度チェック
次のうち、最もよく出題されるデフォルトレベルに関する事実を確認しましょう。
まとめ: 4つのレベルと1つのトレードオフ
4つの分離レベルは、READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLEの順に、弱いものから強いものへと並びます。レベルが1段階上がるごとに、同時実行性を代償として、さらに1つの異常(ダーティ、非反復、ファントム)が禁止されます。
MySQLのREPEATABLE READを除き、デフォルトはREAD COMMITTEDであることを覚えておきましょう。また、実際のエンジンでは標準が要求する以上の異常を防ぐこともあります。次は、これらのレベルが防ぐように設計されている3つの読み取り異常を見ていきます。
よくある質問
「4つの分離レベル」レッスンは無料ですか?
はい。「4つの分離レベル」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Coding Interview Prepコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Coding Interview Prepコースには全4レッスンが含まれています。
「4つの分離レベル」で何を学びますか?
Read UncommittedからSerializableまで、それぞれで許可される動作を学びます。 ブラウザで直接実行するハンズオンコードでCoding Interview Prepを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Coding Interview Prepを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのCoding Interview Prepは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「4つの分離レベル」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このCoding Interview Prepレッスンでコードを書いて実行できますか?
はい。すべてのCoding Interview Prepレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。