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 つのコア要素によって成り立っています。
| # | コンポーネント | 主な役割 | メモリ/ディスク |
|---|---|---|---|
| 1 | Buffer Pool | データページのキャッシュ | メモリ |
| 2 | Redo Log | クラッシュリカバリ用の再実行ログ | ディスク(一部メモリ) |
| 3 | Undo 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/>非同期でディスクへ書き込み
このシーケンス図から、更新処理が以下の流れで実行されることがわかります。
- Buffer Pool でデータページを探す(なければディスクから読み込む)
- Undo Log に変更前のデータを保存
- Buffer Pool 内でページを更新
- Redo Log に変更内容を記録
- クライアントに完了を通知
ディスクへの実際の書き込みは非同期で行われるため、高速な応答が可能になります。
解決策 1:Buffer Pool でディスク I/O を削減
Buffer Pool の役割
Buffer Pool は、InnoDB が管理するメモリ上の巨大なキャッシュ領域です。ディスクから読み込んだデータページ(デフォルトで 16KB)をメモリに保持し、再利用することで、ディスクアクセスを劇的に削減します。
Buffer Pool の主要機能
| # | 機能 | 説明 |
|---|---|---|
| 1 | ページキャッシュ | テーブルやインデックスのデータページを保持 |
| 2 | LRU 管理 | 最近使われていないページを自動的に削除 |
| 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 が再起動すると、以下の手順で自動的にリカバリが実行されます。
- Redo Log を先頭から読み込む
- チェックポイント以降の変更をすべて再実行
- Buffer Pool とディスク上のデータを一致させる
- 通常運用を開始
この仕組みにより、コミット済みのトランザクションは確実に復元されます。
##解決策 3:Undo Log でロールバックと MVCC を実現
Undo Log の役割
Undo Log は、トランザクションのロールバックと、MVCC(Multi-Version Concurrency Control)を実現するための「変更前データの記録」です。
Undo Log の主要機能
| # | 機能 | 説明 |
|---|---|---|
| 1 | ロールバック | エラー時にトランザクションを取り消す |
| 2 | MVCC | 読み取りと書き込みがブロックし合わない |
| 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 の役割と特徴を整理します。
| # | コンポーネント | 主な目的 | 保存場所 | データ内容 |
|---|---|---|---|---|
| 1 | Buffer Pool | ディスク I/O 削減 | メモリ | データページのキャッシュ |
| 2 | Redo Log | クラッシュリカバリ | ディスク | 変更内容(再実行可能) |
| 3 | Undo 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;
内部で起きていること
- InnoDB が Buffer Pool で
id=1のページを検索 - ページがキャッシュにない場合、ディスクから読み込み
- Buffer Pool にページをロード
- クライアントに
balance = 1000.00を返却
この時点で、データは Buffer Pool 上に存在します。
ステップ 2:データの更新
次に、残高を更新します。
sql-- 残高を 500 引く
UPDATE users SET balance = balance - 500 WHERE id = 1;
内部で起きていること
-
Undo Log に変更前データを記録
id=1の古いレコード(balance=1000.00)を Undo Log に保存- これにより、ロールバックや他のトランザクションからの参照が可能になる
-
Buffer Pool 上でページを更新
id=1のbalanceを500.00に書き換え- このページは「ダーティページ」としてマーク(ディスクに未保存)
-
Redo Log に変更内容を記録
- 「
id=1のbalanceを500.00に変更した」という情報を Redo Log に追記 - この時点で、クラッシュリカバリが可能になる
- 「
この段階では、まだディスクの実データファイルには書き込まれていません。
ステップ 3:トランザクションのコミット
sql-- トランザクションをコミット
COMMIT;
内部で起きていること
-
Redo Log をディスクにフラッシュ
innodb_flush_log_at_trx_commit=1の場合、Redo Log を確実にディスクに書き込む- これにより、クラッシュしてもデータを復元できることが保証される
-
クライアントに完了を通知
- この時点でトランザクションは「永続化された」と見なされる
-
ダーティページは非同期で書き込み
- 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 が再起動すると、以下の処理が自動実行されます。
- Redo Log を読み込む
- 「
id=1のbalanceを500.00に変更」を再実行 - データファイルを
balance=500.00に更新 - リカバリ完了、通常運用開始
このように、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 特性を完全に満たすデータベースを実現しています。
パフォーマンスチューニングのポイント
実際の運用では、以下のポイントに注目してチューニングを行いましょう。
| # | チェック項目 | 推奨値 | 確認方法 |
|---|---|---|---|
| 1 | Buffer Pool ヒット率 | 99% 以上 | SHOW STATUS LIKE 'Innodb_buffer_pool%' |
| 2 | Buffer Pool サイズ | 物理メモリの 70-80% | SHOW VARIABLES LIKE 'innodb_buffer_pool_size' |
| 3 | Redo Log サイズ | 1GB ~ 4GB(負荷に応じて) | SHOW VARIABLES LIKE 'innodb_log_file_size' |
| 4 | Undo ログの肥大化 | 定期的にトランケート | SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME='trx_rseg_history_len' |
これらの指標を定期的にモニタリングし、ワークロードに応じて調整することが重要です。
次のステップ
InnoDB の内部構造を理解したことで、以下のような発展的なトピックにも取り組めるようになります。
- クラスタインデックスとセカンダリインデックスの仕組み
- トランザクション分離レベルの内部実装
- デッドロックの検出と解決メカニズム
- パーティショニングとシャーディングの設計
InnoDB は非常に洗練されたストレージエンジンであり、その内部を理解することで、より効率的なデータベース設計とトラブルシューティングが可能になります。
ぜひ、本記事で学んだ知識を実際の開発や運用に活かしてみてください。
関連リンク
articleMySQL InnoDB 内部構造入門:Buffer Pool/Undo/Redo を俯瞰
articleMySQL アラート設計としきい値:レイテンシ・エラー率・レプリカ遅延の基準
articleMySQL 読み書き分離設計:ProxySQL で一貫性とスループットを両立
articleMySQL オプティマイザヒント早見表:/\*+ NO_MERGE, INDEX, HASH_JOIN \*/ 実例集
articleMySQL Shell(mysqlsh)入門:AdminAPI で InnoDB Cluster を最短構築
articleMySQL Optimizer Hints 実測比較:INDEX_MERGE/NO_RANGE_OPTIMIZATION ほか
articleGitHub Copilot Workspace 速理解:仕様 → タスク分解 →PR までの“自動開発”体験
articleMySQL InnoDB 内部構造入門:Buffer Pool/Undo/Redo を俯瞰
articleMotion(旧 Framer Motion)で学ぶ物理ベースアニメ:バネ定数・減衰・質量の直感入門
articleJavaScript Web Animations API:滑らかに動く UI を設計するための基本と実践
articleGitHub Actions コンテキスト辞典:github/env/runner/secrets の使い分け最速理解
articlehtmx で管理画面 CRUD を 10 倍速に:一覧・検索・編集・バルク操作テンプレ
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来