変更を元に戻すための記録
undoログは、トランザクションの変更を「元に戻すための情報」を記録する仕組みです。InnoDBでは主に2つの用途があります。
1つはROLLBACK時の取り消しです。トランザクションがコミットされずに終わった場合、そのトランザクションが行った変更をundoログに基づいて打ち消し、データを変更前の状態へ戻します。
もう1つはMVCC(Multi-Version Concurrency Control)です。ある時点のスナップショットを見ている読み取りからは、他のトランザクションがすでにコミットした最新の行が「まだ見えてはいけない」ことがあります。そのとき、undoログに残された古いバージョンをたどって、その読み取りから見えるべきバージョンを復元します。
redoログとの役割の違い
undoログとredoログは名前が似ていますが、記録するものが正反対です。redoログは「何を変更したか」を物理的に記録し、クラッシュ後に変更を再現するために使います。undoログは「変更をどう取り消すか」を論理的に記録し、ROLLBACKや古いバージョンの復元に使います。
両者は補い合う関係でもあります。通常の(永続テーブル向けの)undoログへの書き込み自体もredoログに記録されるため、undoの永続性はredoによって保証されます。クラッシュ後のリカバリでredoを適用してundoログを復元し、それから未コミットのトランザクションをundoで巻き戻す、という流れになります。なお、ユーザー一時テーブル向けのundoはクラッシュリカバリに不要なため、redoには記録されません。
どこに保存されるか
undoログは、rollback segmentが保持します。MySQL 8.0では専用のundoテーブルスペース(初期化時に既定で2つ作られる)に置かれ、システムテーブルスペース(ibdata1)には格納されません。undoログがibdata1に置かれていたのは主にMySQL 5.7以前です。rollback segmentはINSERT用とUPDATE用のundoログを持ち、各undoログのレコードは、通常のインデックスページと同じ16KB単位のundoページに記録されます。
1つのトランザクションが複数の変更を行うと、そのトランザクションに属するundoログは連鎖状につながります。ROLLBACK時には、この連鎖を逆にたどることで、変更を順に取り消していけます。
2種類のundoログ
undoログは、操作の種類に応じて2つに大別されます。
| 種類 | 役割 |
|---|---|
| INSERTのundo | 行の挿入を取り消すための情報。ROLLBACK時に挿入したレコードを削除する |
| UPDATEのundo | 行の更新・削除を取り消すための情報。ROLLBACK時に更新前の値を復元する。並行する読み取りで古いバージョンを復元するときにも使う |
この2つは、寿命の扱いも違います。INSERTのundoはROLLBACK専用なので、トランザクションがコミットされれば破棄されるか、再利用のためにキャッシュされます。挿入した行は、コミットしてしまえば「元に戻す」必要も「古いバージョンとして見せる」必要もないからです。
一方、UPDATEのundoはhistory listに入り、まだ古いバージョンを参照しているRead Viewがある間は保持されます。不要になったあと、purgeによって回収されます。更新前の値は、まだ古いスナップショットを見ている読み取りにとって必要になり得るため、コミット後すぐには捨てられないわけです。