T-CREATOR

MySQL InnoDB 内部構造入門:Buffer Pool/Undo/Redo を俯瞰

MySQL InnoDB 内部構造入門:Buffer Pool/Undo/Redo を俯瞰

MySQL の InnoDB ストレージエンジンは、高いパフォーマンスと堅牢性を兼ね備えたデータベースの心臓部です。その裏側では、Buffer Pool、Undo Log、Redo Log という 3 つの重要な仕組みが、データの整合性を保ちながら高速な読み書きを実現しています。

本記事では、InnoDB の内部構造について初心者の方にもわかりやすく解説します。特に「なぜディスクではなくメモリで処理するのか」「障害時にどうやってデータを守るのか」といった疑問に答えながら、これら 3 つの仕組みの役割と連携を俯瞰していきましょう。

背景

データベースが直面するパフォーマンスの壁

データベースシステムは、大量のデータを永続化しながら、高速な読み書き性能を求められます。しかし、ディスクへの直接アクセスは CPU やメモリに比べて圧倒的に遅く、ボトルネックになりがちです。

たとえば、メモリアクセスが数十ナノ秒で完了するのに対し、ディスクアクセスは数ミリ秒かかります。この差は約 100 万倍 にも及びます。

InnoDB が採用する基本戦略

InnoDB は、この性能差を埋めるために以下の戦略を採用しています。

  • メモリ上でデータを扱う:頻繁にアクセスするデータをメモリにキャッシュ(Buffer Pool)
  • 更新処理を遅延させる:ディスクへの書き込みをまとめて効率化
  • 障害に備える:クラッシュ時でもデータを復旧できる仕組み(Redo Log、Undo Log)

以下の図で、InnoDB の基本的なデータフローを確認しましょう。

mermaidflowchart TB
  client["クライアント<br/>アプリケーション"] -->|SQL クエリ| innodb["InnoDB エンジン"]
  innodb -->|読み取り要求| bp["Buffer Pool<br/>(メモリキャッシュ)"]
  bp -->|キャッシュミス| disk1[("ディスク<br/>データファイル")]
  disk1 -->|ページ読み込み| bp
  innodb -->|更新処理| bp
  bp -->|変更ページ| dirty["ダーティページ<br/>(未保存データ)"]
  dirty -->|非同期書き込み| disk1
  innodb -->|トランザクション記録| redo["Redo Log<br/>(再実行ログ)"]
  innodb -->|変更前データ| undo["Undo Log<br/>(ロールバック用)"]
  redo -->|定期的にフラッシュ| disk2[("ディスク<br/>Redo Log ファイル")]
  undo -->|保存| disk3[("ディスク<br/>Undo 領域")]

この図から、InnoDB が「読み取りも書き込みもまずメモリで処理し、ディスクへの書き込みは非同期で行う」という設計思想が見えてきますね。

各コンポーネントの役割概要

InnoDB の内部構造は、以下の 3 つのコア要素によって成り立っています。

#コンポーネント主な役割メモリ/ディスク
1Buffer Poolデータページのキャッシュメモリ
2Redo Logクラッシュリカバリ用の再実行ログディスク(一部メモリ)
3Undo Logトランザクションのロールバック情報ディスク(一部メモリ)

これらが連携することで、InnoDB は高速性とデータ保護の両立を実現しています。

課題

データベースが解決すべき 3 つの課題

InnoDB のような高性能データベースを設計する際、以下の 3 つの課題を同時に解決する必要があります。

課題 1:ディスク I/O のボトルネック

すべてのデータアクセスをディスクに依存すると、システム全体のパフォーマンスが著しく低下します。特に、小さなデータを頻繁に読み書きする OLTP(オンライン・トランザクション処理)では致命的です。

具体的な問題点

  • ディスクのシークタイムが遅い(HDD の場合、数ミリ秒)
  • ランダムアクセスの性能が低い
  • 1 回の読み書きで小さなデータしか扱えない

課題 2:障害時のデータ保護

データベースは突然のサーバークラッシュや電源断に直面する可能性があります。その際、以下の条件を満たす必要があります。

ACID 特性の保証

  • Atomicity(原子性):トランザクションは全て成功するか、全て失敗するか
  • Consistency(一貫性):データの整合性を常に保つ
  • Isolation(分離性):複数のトランザクションが互いに干渉しない
  • Durability(永続性):コミットされたデータは障害後も失われない

課題 3:同時実行制御とロールバック

複数のユーザーが同時にデータを更新する環境では、以下の機能が必須です。

  • MVCC(Multi-Version Concurrency Control):読み取りと書き込みがブロックし合わない
  • ロールバック:エラー発生時に変更を取り消せる
  • 一貫性のある読み取り:トランザクション開始時点のデータを参照できる

以下の図で、これら 3 つの課題がどう関連しているかを確認しましょう。

mermaidflowchart TD
  problem["データベースの<br/>3 つの課題"]
  problem --> p1["課題 1<br/>ディスク I/O<br/>ボトルネック"]
  problem --> p2["課題 2<br/>障害時の<br/>データ保護"]
  problem --> p3["課題 3<br/>同時実行制御と<br/>ロールバック"]

  p1 --> s1["解決策:<br/>Buffer Pool"]
  p2 --> s2["解決策:<br/>Redo Log"]
  p3 --> s3["解決策:<br/>Undo Log"]

  s1 --> result["高速 + 堅牢な<br/>データベース"]
  s2 --> result
  s3 --> result

この図が示すように、InnoDB の 3 つのコア要素は、それぞれ異なる課題を解決するために設計されています。次のセクションでは、それぞれの解決策を詳しく見ていきましょう。

課題の相互依存性

これらの課題は独立しているわけではありません。たとえば、Buffer Pool だけでパフォーマンスを向上させても、クラッシュ時にメモリ上のデータが失われてしまえば意味がありません。

そのため、InnoDB は 3 つの仕組みを巧妙に組み合わせることで、すべての課題を同時に解決しているのです。

解決策

InnoDB の 3 本柱による統合的アプローチ

InnoDB は、前述の 3 つの課題に対して、Buffer Pool、Redo Log、Undo Log という専用の仕組みをそれぞれ配置しています。これらは独立して動作するのではなく、密接に連携することで、高速性と堅牢性を両立させています。

以下の図で、3 つのコンポーネントがどのように連携しているかを確認しましょう。

mermaidsequenceDiagram
  participant C as クライアント
  participant I as InnoDB エンジン
  participant BP as Buffer Pool
  participant RL as Redo Log
  participant UL as Undo Log
  participant D as ディスク

  C->>I: UPDATE クエリ実行
  I->>BP: 該当ページを検索
  alt ページがキャッシュにない
    BP->>D: ディスクからページ読み込み
    D-->>BP: ページデータ返却
  end
  I->>UL: 変更前データを記録
  I->>BP: ページを更新(ダーティページ化)
  I->>RL: 変更内容を Redo Log に記録
  I-->>C: 更新完了(COMMIT)
  Note over RL,D: Redo Log は定期的に<br/>ディスクへフラッシュ
  Note over BP,D: ダーティページは<br/>非同期でディスクへ書き込み

このシーケンス図から、更新処理が以下の流れで実行されることがわかります。

  1. Buffer Pool でデータページを探す(なければディスクから読み込む)
  2. Undo Log に変更前のデータを保存
  3. Buffer Pool 内でページを更新
  4. Redo Log に変更内容を記録
  5. クライアントに完了を通知

ディスクへの実際の書き込みは非同期で行われるため、高速な応答が可能になります。

解決策 1:Buffer Pool でディスク I/O を削減

Buffer Pool の役割

Buffer Pool は、InnoDB が管理するメモリ上の巨大なキャッシュ領域です。ディスクから読み込んだデータページ(デフォルトで 16KB)をメモリに保持し、再利用することで、ディスクアクセスを劇的に削減します。

Buffer Pool の主要機能

#機能説明
1ページキャッシュテーブルやインデックスのデータページを保持
2LRU 管理最近使われていないページを自動的に削除
3ダーティページ管理更新されたがディスクに未保存のページを追跡
4プリフェッチ連続アクセスを予測して先読み

Buffer Pool の構造

Buffer Pool は以下のような構造で管理されています。

mermaidflowchart LR
  subgraph bp["Buffer Pool(メモリ領域)"]
    direction TB
    new["新規読み込みページ<br/>(Young 領域)"]
    old["古いページ<br/>(Old 領域)"]
    dirty["ダーティページ<br/>リスト"]
  end

  disk[("ディスク")]
  client["クライアント要求"]

  client -->|読み取り| new
  disk -->|ページ読み込み| new
  new -->|時間経過| old
  old -->|再アクセス| new
  old -->|追い出し| disk
  client -->|更新| dirty
  dirty -->|フラッシュ| disk

この図が示すように、Buffer Pool は LRU(Least Recently Used)アルゴリズムの改良版を使って、効率的にページを管理しています。

Buffer Pool のサイズ設定

Buffer Pool のサイズは、MySQL のパフォーマンスに直接影響します。一般的には、サーバーの物理メモリの 70 ~ 80% を割り当てることが推奨されます。

sql-- Buffer Pool のサイズを確認
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
sql-- Buffer Pool のサイズを設定(8GB の例)
SET GLOBAL innodb_buffer_pool_size = 8589934592;

設定は my.cnf または my.ini ファイルで永続化できます。

ini[mysqld]
# Buffer Pool サイズを 8GB に設定
innodb_buffer_pool_size = 8G

# Buffer Pool のインスタンス数(並列処理を改善)
innodb_buffer_pool_instances = 8

解決策 2:Redo Log でクラッシュリカバリを実現

Redo Log の役割

Redo Log は、InnoDB が障害からデータを復旧するための「再実行ログ」です。Buffer Pool 上で行われたすべての変更を、順次ディスクに書き込むことで、クラッシュ時にデータを復元できます。

WAL(Write-Ahead Logging)の原則

InnoDB は WAL(Write-Ahead Logging)という手法を採用しています。これは、データページをディスクに書き込む前に、必ず Redo Log に変更内容を記録するという原則です。

WAL のメリット

  • ランダムアクセスではなく、順次書き込みで高速化
  • 小さなログファイルに書き込むため、I/O 負荷が低い
  • クラッシュ時に Redo Log を再実行すれば、データを復元できる

Redo Log の構造

Redo Log は循環バッファとして実装されています。

mermaidflowchart LR
  subgraph redo["Redo Log(循環バッファ)"]
    direction LR
    log1["ib_logfile0"]
    log2["ib_logfile1"]
    log1 -->|書き込み完了| log2
    log2 -->|書き込み完了| log1
  end

  innodb["InnoDB エンジン"]
  checkpoint["チェックポイント<br/>(安全に上書き可能な位置)"]

  innodb -->|変更を記録| log1
  innodb -->|変更を記録| log2
  log1 -.->|古いログを上書き| checkpoint
  log2 -.->|古いログを上書き| checkpoint

Redo Log は固定サイズのファイルを循環利用します。チェックポイントより前のログは、すでにディスクに反映済みなので、安全に上書きできます。

Redo Log の設定

Redo Log のサイズと動作は、以下のパラメータで制御できます。

sql-- Redo Log の設定を確認
SHOW VARIABLES LIKE 'innodb_log%';
ini[mysqld]
# Redo Log ファイルのサイズ(1GB の例)
innodb_log_file_size = 1G

# Redo Log ファイルの数
innodb_log_files_in_group = 2

# Redo Log のフラッシュタイミング
# 0: 約 1 秒ごとにフラッシュ(高速だが障害時にデータ損失の可能性)
# 1: トランザクションごとにフラッシュ(安全だが低速)
# 2: トランザクションごとに OS にフラッシュ要求(バランス型)
innodb_flush_log_at_trx_commit = 1

本番環境では、データの安全性を重視して innodb_flush_log_at_trx_commit = 1 に設定することが推奨されます。

クラッシュリカバリの流れ

サーバーがクラッシュした後、MySQL が再起動すると、以下の手順で自動的にリカバリが実行されます。

  1. Redo Log を先頭から読み込む
  2. チェックポイント以降の変更をすべて再実行
  3. Buffer Pool とディスク上のデータを一致させる
  4. 通常運用を開始

この仕組みにより、コミット済みのトランザクションは確実に復元されます。

##解決策 3:Undo Log でロールバックと MVCC を実現

Undo Log の役割

Undo Log は、トランザクションのロールバックと、MVCC(Multi-Version Concurrency Control)を実現するための「変更前データの記録」です。

Undo Log の主要機能

#機能説明
1ロールバックエラー時にトランザクションを取り消す
2MVCC読み取りと書き込みがブロックし合わない
3一貫性のある読み取りトランザクション開始時点のデータを参照
4古いバージョンの管理実行中トランザクションに必要な履歴を保持

MVCC の仕組み

MVCC により、InnoDB は読み取りトランザクションが書き込みトランザクションをブロックしない(その逆も然り)という特性を持っています。

mermaidsequenceDiagram
  participant T1 as トランザクション 1<br/>(読み取り)
  participant T2 as トランザクション 2<br/>(更新)
  participant BP as Buffer Pool
  participant UL as Undo Log

  T1->>BP: SELECT(ID=100)開始
  Note over T1: 現在の値 = "Alice"
  T2->>BP: UPDATE(ID=100)開始
  T2->>UL: 変更前データ "Alice" を保存
  T2->>BP: 新しい値 "Bob" に更新
  T2->>BP: COMMIT
  T1->>UL: 過去のバージョンを読み取り
  UL-->>T1: "Alice" を返却
  T1->>T1: COMMIT
  Note over T1: T1 は "Alice" を読み取った<br/>(T2 の変更は見えない)

このように、トランザクション 1 が開始した時点のデータを、トランザクション 2 の更新後も読み取れるのが MVCC の特徴です。

Undo Log の構造

Undo Log は、システムテーブルスペース内または専用の Undo テーブルスペースに保存されます。

mermaidflowchart TB
  subgraph undo["Undo Log 領域"]
    direction TB
    seg1["Undo セグメント 1"]
    seg2["Undo セグメント 2"]
    seg3["Undo セグメント ..."]
  end

  tx1["トランザクション 1"] -->|変更前データ| seg1
  tx2["トランザクション 2"] -->|変更前データ| seg2
  tx3["トランザクション 3"] -->|変更前データ| seg3

  purge["Purge スレッド"]
  purge -.->|不要な履歴を削除| seg1
  purge -.->|不要な履歴を削除| seg2
  purge -.->|不要な履歴を削除| seg3

Purge スレッドが、どのトランザクションからも参照されなくなった古い Undo レコードを定期的に削除します。

Undo Log の設定

MySQL 8.0 以降では、Undo Log を専用のテーブルスペースに分離できます。

sql-- Undo Log のテーブルスペースを確認
SELECT TABLESPACE_NAME, FILE_NAME
FROM INFORMATION_SCHEMA.FILES
WHERE TABLESPACE_NAME LIKE 'innodb_undo%';
sql-- 新しい Undo テーブルスペースを作成
CREATE UNDO TABLESPACE undo_003 ADD DATAFILE 'undo_003.ibu';
ini[mysqld]
# Undo テーブルスペースの数
innodb_undo_tablespaces = 2

# Undo ログのトランケート(自動削減)を有効化
innodb_undo_log_truncate = ON

# Undo ログの最大サイズ(1GB を超えるとトランケート)
innodb_max_undo_log_size = 1G

3 つの仕組みの連携まとめ

以下の表で、Buffer Pool、Redo Log、Undo Log の役割と特徴を整理します。

#コンポーネント主な目的保存場所データ内容
1Buffer Poolディスク I/O 削減メモリデータページのキャッシュ
2Redo Logクラッシュリカバリディスク変更内容(再実行可能)
3Undo Logロールバック/MVCCディスク変更前データ

これら 3 つが協調動作することで、InnoDB は「高速」「堅牢」「同時実行性が高い」という特性を実現しています。

具体例

実際の更新処理を追跡してみる

ここでは、具体的な UPDATE 文を例に、InnoDB の内部で何が起きているかを段階的に追跡してみましょう。

前提条件

以下のようなシンプルなテーブルがあるとします。

sql-- テーブル定義
CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(100),
  balance DECIMAL(10, 2)
) ENGINE=InnoDB;
sql-- 初期データ
INSERT INTO users VALUES (1, 'Alice', 1000.00);

現在、id=1 のレコードは以下の状態です。

textid: 1
name: Alice
balance: 1000.00

ステップ 1:トランザクション開始と読み取り

クライアントが以下のトランザクションを開始します。

sql-- トランザクション開始
START TRANSACTION;
sql-- 残高を確認
SELECT balance FROM users WHERE id = 1;

内部で起きていること

  1. InnoDB が Buffer Pool で id=1 のページを検索
  2. ページがキャッシュにない場合、ディスクから読み込み
  3. Buffer Pool にページをロード
  4. クライアントに balance = 1000.00 を返却

この時点で、データは Buffer Pool 上に存在します。

ステップ 2:データの更新

次に、残高を更新します。

sql-- 残高を 500 引く
UPDATE users SET balance = balance - 500 WHERE id = 1;

内部で起きていること

  1. Undo Log に変更前データを記録

    • id=1 の古いレコード(balance=1000.00)を Undo Log に保存
    • これにより、ロールバックや他のトランザクションからの参照が可能になる
  2. Buffer Pool 上でページを更新

    • id=1balance500.00 に書き換え
    • このページは「ダーティページ」としてマーク(ディスクに未保存)
  3. Redo Log に変更内容を記録

    • id=1balance500.00 に変更した」という情報を Redo Log に追記
    • この時点で、クラッシュリカバリが可能になる

この段階では、まだディスクの実データファイルには書き込まれていません。

ステップ 3:トランザクションのコミット

sql-- トランザクションをコミット
COMMIT;

内部で起きていること

  1. Redo Log をディスクにフラッシュ

    • innodb_flush_log_at_trx_commit=1 の場合、Redo Log を確実にディスクに書き込む
    • これにより、クラッシュしてもデータを復元できることが保証される
  2. クライアントに完了を通知

    • この時点でトランザクションは「永続化された」と見なされる
  3. ダーティページは非同期で書き込み

    • Buffer Pool 内のダーティページは、後でまとめてディスクに書き込まれる
    • 書き込みタイミングは InnoDB が自動的に最適化

以下の図で、この一連の流れを確認しましょう。

mermaidflowchart TD
  start["トランザクション開始<br/>START TRANSACTION"] --> select["SELECT balance<br/>(Buffer Pool から読み取り)"]
  select --> update["UPDATE balance<br/>(更新処理開始)"]

  update --> undo["Undo Log に<br/>変更前データ記録<br/>balance=1000.00"]
  undo --> bp["Buffer Pool 上で<br/>ページ更新<br/>balance=500.00"]
  bp --> redo["Redo Log に<br/>変更内容記録"]

  redo --> commit["COMMIT"]
  commit --> flush["Redo Log を<br/>ディスクにフラッシュ"]
  flush --> done["完了通知<br/>(トランザクション確定)"]

  bp -.->|非同期| diskwrite["ダーティページを<br/>ディスクに書き込み"]

この図が示すように、COMMIT 時にディスクに書き込まれるのは Redo Log だけで、実データはあとで非同期に書き込まれます。

ステップ 4:クラッシュとリカバリのシミュレーション

もし、COMMIT 直後にサーバーがクラッシュしたとしましょう。この時点で、ダーティページはまだディスクに書き込まれていません。

クラッシュ直前の状態

  • Buffer Pool(メモリ)balance=500.00(消失)
  • Redo Log(ディスク)balance=500.00 に変更した記録(保存済み)
  • データファイル(ディスク)balance=1000.00(古いまま)

リカバリ時の動作

MySQL が再起動すると、以下の処理が自動実行されます。

  1. Redo Log を読み込む
  2. id=1balance500.00 に変更」を再実行
  3. データファイルを balance=500.00 に更新
  4. リカバリ完了、通常運用開始

このように、Redo Log があれば、コミット済みのトランザクションは確実に復元できます。

複数トランザクションの同時実行例

次に、MVCC の動作を確認するため、2 つのトランザクションを同時実行してみましょう。

トランザクション A:長時間実行される読み取り

sql-- トランザクション A 開始
START TRANSACTION;

-- 残高を確認(この時点で balance=1000.00)
SELECT balance FROM users WHERE id = 1;
-- 結果:1000.00

-- ... 何か処理をしている間 ...

トランザクション B:同じレコードを更新

sql-- トランザクション B 開始
START TRANSACTION;

-- 残高を更新
UPDATE users SET balance = balance - 300 WHERE id = 1;

-- コミット
COMMIT;
-- この時点で、balance は 700.00 に更新される

トランザクション A:再度読み取り

sql-- トランザクション A で再度読み取り
SELECT balance FROM users WHERE id = 1;
-- 結果:1000.00(B の変更は見えない!)

COMMIT;

なぜトランザクション A は古い値を読めるのか

トランザクション A が開始した時点のスナップショットを、Undo Log を使って再構築しているためです。

mermaidsequenceDiagram
  participant A as トランザクション A
  participant B as トランザクション B
  participant BP as Buffer Pool
  participant UL as Undo Log

  A->>BP: START TRANSACTION<br/>(スナップショット作成)
  A->>BP: SELECT balance(1000.00)
  B->>BP: START TRANSACTION
  B->>UL: 変更前データ保存<br/>balance=1000.00
  B->>BP: UPDATE balance=700.00
  B->>BP: COMMIT
  Note over BP: 最新データは 700.00
  A->>UL: 過去バージョン要求
  UL-->>A: balance=1000.00
  A->>A: COMMIT

この仕組みにより、読み取りトランザクションが更新トランザクションをブロックすることなく、一貫性のあるデータを読み取れます。

パフォーマンスチューニングの実例

最後に、Buffer Pool のヒット率を確認して、パフォーマンスチューニングを行う方法を紹介します。

Buffer Pool のヒット率を確認

sql-- Buffer Pool の統計情報を取得
SHOW STATUS LIKE 'Innodb_buffer_pool%';

重要な指標は以下の 2 つです。

sql-- 読み取り要求の総数
SELECT VARIABLE_VALUE AS total_reads
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests';
sql-- ディスクから読み込んだ回数(キャッシュミス)
SELECT VARIABLE_VALUE AS disk_reads
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads';

ヒット率の計算

sql-- Buffer Pool ヒット率を計算
SELECT
  ROUND(
    (1 - (
      (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') /
      (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests')
    )) * 100, 2
  ) AS hit_rate_percent;

理想的には、ヒット率は 99% 以上 であることが望ましいです。

ヒット率が低い場合の対処法

ヒット率が 95% 未満の場合、以下の対策を検討しましょう。

対策 1:Buffer Pool サイズを増やす

ini[mysqld]
# 現在 4GB なら、8GB に増やす
innodb_buffer_pool_size = 8G

対策 2:不要なクエリを削減

フルテーブルスキャンを行うクエリは、Buffer Pool を圧迫します。インデックスを追加することで改善できます。

sql-- スロークエリログを有効化
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
sql-- スロークエリを確認
SELECT * FROM mysql.slow_log ORDER BY query_time DESC LIMIT 10;

対策 3:Buffer Pool のインスタンス数を調整

大きな Buffer Pool を使用する場合、複数のインスタンスに分割することで、並列処理性能が向上します。

ini[mysqld]
# 8GB 以上なら、8 インスタンスに分割
innodb_buffer_pool_instances = 8

Redo Log のサイズ最適化

Redo Log が小さすぎると、頻繁にチェックポイントが発生し、パフォーマンスが低下します。

Redo Log の使用状況を確認

sql-- Redo Log の状態を確認
SHOW ENGINE INNODB STATUS\G

出力の中で、以下のような行を探します。

textLog sequence number          123456789
Log flushed up to            123456700
Last checkpoint at           123456500

チェックポイントの頻度が高い場合

チェックポイントが 1 分に何度も発生する場合、Redo Log サイズを増やすことを検討しましょう。

ini[mysqld]
# Redo Log を 1GB に増やす
innodb_log_file_size = 1G

変更後は、MySQL を再起動する必要があります。

まとめ

本記事では、MySQL InnoDB の内部構造を構成する 3 つのコア要素、Buffer Pool、Redo Log、Undo Log について詳しく解説しました。

3 つの仕組みの役割

  • Buffer Pool:ディスク I/O を削減し、メモリ上で高速にデータを処理
  • Redo Log:クラッシュリカバリを実現し、障害時にコミット済みデータを復元
  • Undo Log:トランザクションのロールバックと MVCC を実現し、一貫性のある読み取りを提供

これら 3 つは独立して動作するのではなく、密接に連携することで、InnoDB の「高速」「堅牢」「高同時実行性」という特性を支えています。

設計思想の本質

InnoDB の設計思想を一言でまとめると、「ディスクではなくメモリで処理し、ログで安全性を保証する」 ということになります。

この思想により、レスポンスタイムを犠牲にすることなく、ACID 特性を完全に満たすデータベースを実現しています。

パフォーマンスチューニングのポイント

実際の運用では、以下のポイントに注目してチューニングを行いましょう。

#チェック項目推奨値確認方法
1Buffer Pool ヒット率99% 以上SHOW STATUS LIKE 'Innodb_buffer_pool%'
2Buffer Pool サイズ物理メモリの 70-80%SHOW VARIABLES LIKE 'innodb_buffer_pool_size'
3Redo Log サイズ1GB ~ 4GB(負荷に応じて)SHOW VARIABLES LIKE 'innodb_log_file_size'
4Undo ログの肥大化定期的にトランケートSELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME='trx_rseg_history_len'

これらの指標を定期的にモニタリングし、ワークロードに応じて調整することが重要です。

次のステップ

InnoDB の内部構造を理解したことで、以下のような発展的なトピックにも取り組めるようになります。

  • クラスタインデックスとセカンダリインデックスの仕組み
  • トランザクション分離レベルの内部実装
  • デッドロックの検出と解決メカニズム
  • パーティショニングとシャーディングの設計

InnoDB は非常に洗練されたストレージエンジンであり、その内部を理解することで、より効率的なデータベース設計とトラブルシューティングが可能になります。

ぜひ、本記事で学んだ知識を実際の開発や運用に活かしてみてください。

関連リンク