MySQL 8.0 リファレンスマニュアル


15.3 InnoDB マルチバージョン

InnoDBマルチバージョンストレージエンジンです。並列実行やロールバックなどのトランザクション機能をサポートするために、変更された行の古いバージョンに関する情報が保持されます。 この情報は、テーブルスペース内にロールバックセグメントと呼ばれるデータ構造で (Oracle では類似したデータ構造のあとに) 格納されます。 InnoDB では、トランザクションのロールバックで必要となる取り消し操作を実行するために、ロールバックセグメント内の情報が使用されます。 また、この情報は、一貫性読み取りのために行の初期バージョンを構築する際にも使用されます。

InnoDB は内部的に、データベース内に格納された各行に 3 つのフィールドを追加します。 6 バイトの DB_TRX_ID フィールドは、行を挿入または更新した最後のトランザクションに対して、トランザクション識別子を指示します。 また、行内の特別ビットが削除されたとマークするように設定されている場合、削除は内部的に更新として処理されます。 各行には、ロールポインタと呼ばれる 7 バイトの DB_ROLL_PTR フィールドも含まれています。 ロールポインタは、ロールバックセグメントに書き込まれた Undo ログレコードを示しています。 行が更新された場合は、Undo ログレコードに、更新される前の行の内容を再構築するために必要な情報が含まれます。 6 バイトの DB_ROW_ID フィールドには、新しい行が挿入されると単調に増加する行 ID が含まれています。 InnoDB によって自動生成されたクラスタ化されたインデックスには、行 ID 値が含まれます。 それ以外の場合、インデックスに DB_ROW_ID カラムが含まれることはありません。

ロールバックセグメント内の Undo ログは、挿入および更新 Undo ログに分割されます。 挿入 Undo ログはトランザクションロールバックでのみ必要であるため、トランザクションのコミット直後に破棄できます。 更新 Undo ログも一貫性読み取りで使用されますが、InnoDB によってスナップショットが割り当てられたトランザクションが存在しなくなったあとでのみ破棄できます。更新 Undo ログ内のスナップショット情報は、データベース行の以前のバージョンを構築する際に一貫性読み取りで必要となる可能性があります。

トランザクション (一貫性読み取りのみを発行するトランザクションを含む) を定期的にコミットしてください。 それ以外の場合は、InnoDB は更新 Undo ログからデータを破棄できないため、ロールバックセグメントが大きくなり過ぎてテーブルスペースがいっぱいになる可能性があります。

一般に、ロールバックセグメント内の Undo ログレコードの物理的サイズは、それに対応する挿入された行や更新された行よりも小さいです。 この情報を使用すると、ロールバックセグメントで必要となる領域を計算できます。

InnoDB マルチバージョンスキームでは、SQL ステートメントで行を削除しても、その行はすぐにデータベースから物理的に削除されません。 InnoDB は、削除用に書き込まれた更新 Undo ログレコードが破棄されたときにのみ、対応する行およびそのインデックスレコードを物理的に削除します。 このような削除操作はパージと呼ばれ、非常に高速です。通常は、削除が行われなかった SQL ステートメントと同じ時系列順で実行されます。

テーブル内で小さめのバッチの行をほぼ同じ速度で挿入および削除すると、すべてのデッド行が原因で、パージスレッドが遅延し始め、増加し続ける可能性があります。これにより、すべてにおいてディスクが抑制され、非常に低速になります。 このような場合は、新たな行操作を抑制し、innodb_max_purge_lag システム変数を調整することで、より多くのリソースをパージスレッドに割り当てます。 詳細は、セクション15.14「InnoDB の起動オプションおよびシステム変数」を参照してください。

マルチバージョニングおよびセカンダリインデックス

InnoDB multiversion concurrency control (MVCC) は、セカンダリインデックスをクラスタ化されたインデックスとは異なる方法で扱います。 クラスタ化されたインデックス内のレコードはインプレースで更新され、非表示のシステムカラムは undo ログエントリを指し、このエントリから以前のバージョンのレコードを再構築できます。 クラスタ化されたインデックスレコードとは異なり、セカンダリインデックスレコードには非表示のシステムカラムは含まれず、インプレースで更新されません。

セカンダリインデックスカラムが更新されると、古いセカンダリインデックスレコードが削除マークされ、新しいレコードが挿入され、削除マークが付けられたレコードが最終的にパージされます。 セカンダリインデックスレコードが削除マークされるか、新しいトランザクションによってセカンダリインデックスページが更新されると、InnoDB はクラスタインデックスでデータベースレコードを検索します。 クラスタインデックスでは、読取りトランザクションの開始後にレコードが変更された場合、レコード DB_TRX_ID がチェックされ、正しいバージョンのレコードが undo ログから取得されます。

セカンダリインデックスレコードが削除対象としてマークされている場合、またはセカンダリインデックスページが新しいトランザクションによって更新されている場合、covering index 手法は使用されません。 InnoDB は、インデックス構造から値を戻すかわりに、クラスタ化されたインデックス内のレコードを検索します。

ただし、index condition pushdown (ICP) の最適化が有効で、WHERE 条件の一部をインデックスのフィールドのみを使用して評価できる場合、MySQL サーバーは WHERE 条件のこの部分を、インデックスを使用して評価されるストレージエンジンにプッシュダウンします。 一致するレコードが見つからない場合、クラスタインデックスルックアップは回避されます。 一致するレコードが見つかった場合、削除マークが付けられたレコードの中でも、InnoDB はクラスタ化されたインデックス内のレコードを検索します。


関連キーワード:  InnoDB, テーブル, インデックス, 構成, トランザクション, レコード, ログ, 更新, 情報, スペース