こんにちは、かつコーチです。
前回はInnoDBとMyISAMというストレージエンジンの違いを扱いました。
この記事は上級者向けとして、ストレージエンジンがMySQL全体のどこに位置づけられているのか、アーキテクチャ全体像から解説します。
トランザクションやロック、インデックスといった基本用語は前提知識として説明を省略し、仕組みと設計判断への活かし方に絞ります。
2層構造のアーキテクチャ
サーバーレイヤーとストレージエンジンレイヤー
MySQLのアーキテクチャは、大きくサーバーレイヤーとストレージエンジンレイヤーの2層に分かれています。
サーバーレイヤーは、接続処理・SQLパース・オプティマイザ・キャッシュなど、どのストレージエンジンを使っても共通で動く処理を担当します。
ストレージエンジンレイヤーは、実際のデータの読み書き・ロック制御・トランザクション管理を担当する、差し替え可能なプラガブルな層です。
前回解説したInnoDB・MyISAMの違いは、まさにこのストレージエンジンレイヤーの実装差にあたります。
なぜレイヤーが分かれているのか
この2層構造のおかげで、アプリケーション側は同じSQL文法・同じ接続方式のまま、テーブルごとに裏側の実装だけを切り替えられます。
チューニングを行う際も、「オプティマイザの挙動を疑うべきか」「ストレージエンジン固有の設定を疑うべきか」を切り分けて考えられるようになり、原因調査の見通しが立てやすくなります。
サーバーレイヤーの内部構造
コネクション層とSQLインターフェース層
クライアントからの接続は、まずコネクション層でスレッドが割り当てられ、認証が行われます。
続くSQLインターフェース層でSQL文が受け取られ、パーサーが構文を解析し、実行計画を組み立てる準備が行われます。
オプティマイザとキャッシュの役割
パースされたSQLはオプティマイザに渡され、どのインデックスを使うか、どの順序でテーブルを結合するかといった実行計画が決定されます。
EXPLAINで確認できる実行計画は、まさにこのオプティマイザが導き出した結果です。
MySQL 8.0では、5.7系まで存在したクエリキャッシュが廃止されています。
複数コアでの同時実行時にクエリキャッシュがボトルネックになりやすかったことが主な理由で、8.0以降はアプリケーション側やRedisなどのミドルウェアでキャッシュ戦略を組む設計が前提になっています。
過去に5.7系からのアップグレード案件で、クエリキャッシュに依存したパフォーマンス設計のままアプリを移行し、想定より応答が遅くなったケースに遭遇したことがあります。
バージョンアップ時は、クエリキャッシュ廃止の影響を必ず確認すべきポイントです。
ストレージエンジンレイヤーとInnoDBの内部構造
バッファプールという中核コンポーネント
InnoDBの内部で特に重要なのがバッファプールです。
バッファプールは、ディスク上のデータやインデックスをメモリ上にキャッシュしておく領域で、innodb_buffer_pool_sizeという設定値でサイズを調整します。
[mysqld]
innodb_buffer_pool_size = 4G
バッファプールに載りきらないデータへのアクセスが多いと、ディスクI/Oが頻発してパフォーマンスが大きく低下します。
実務のチューニングでは、専用サーバーであればバッファプールを物理メモリの50〜70%程度に設定するのが1つの目安とされていますが、他プロセスとの共存状況に応じて調整が必要です。
REDOログとトランザクションの永続性
InnoDBがクラッシュ後もデータを復旧できるのは、REDOログという仕組みのおかげです。
トランザクションがコミットされる際、変更内容はまずREDOログに書き込まれ、その後バッファプール上のデータページに反映されます。
サーバーが突然クラッシュしても、REDOログを再生することで、コミット済みのデータを復元できます。
前回の記事で触れたMyISAMのクラッシュ事例は、このREDOログの仕組みを持たないことが根本原因でした。
アダプティブハッシュインデックス
InnoDBは、頻繁にアクセスされるB-Treeインデックスの一部を、内部で自動的にアダプティブハッシュインデックスというハッシュ構造に変換し、検索を高速化する機能を持っています。
これはDBA側で明示的に作成するものではなく、アクセスパターンに応じてMySQLが自動的に管理する仕組みです。
SHOW ENGINE INNODB STATUSを実行すると、この機能の利用状況を含めたInnoDBの内部統計情報を確認できます。
アーキテクチャ理解を設計判断に活かす
書き込み負荷とバッファプールのサイジング
書き込みが多いシステムでは、REDOログの書き込み設定(innodb_flush_log_at_trx_commit)とバッファプールのサイジングが、性能とデータ安全性のトレードオフに直結します。
innodb_flush_log_at_trx_commit=1(デフォルト)はコミットごとにディスクへ同期し、最も安全ですがI/O負荷は高くなります。
多少のデータロストを許容してでも書き込みスループットを優先する場合、値を2に変更するという選択肢もありますが、これはデータ損失リスクを正しく理解した上で判断すべき設定です。
レイヤー構造を踏まえたトラブルシューティング
パフォーマンス問題に直面したとき、「オプティマイザが非効率な実行計画を選んでいるのか」「ストレージエンジンレイヤーでI/Oがボトルネックになっているのか」を切り分けることが、原因究明の第一歩になります。
EXPLAINはサーバーレイヤーの実行計画を、SHOW ENGINE INNODB STATUSはストレージエンジンレイヤーの内部状態を確認するためのツールと位置づけると、両者の使い分けが明確になります。
まとめ
この記事のポイント
- MySQLはサーバーレイヤーとストレージエンジンレイヤーの2層構造で、後者は差し替え可能
- サーバーレイヤーはコネクション・パース・オプティマイザを担い、MySQL 8.0ではクエリキャッシュが廃止された
- InnoDBはバッファプールとREDOログを中核とし、クラッシュ耐性とトランザクションを支えている
- レイヤー構造を理解すると、パフォーマンス問題の原因切り分けがしやすくなる
次に読むべき記事
アーキテクチャの内部構造を理解したところで、次は実務で必ずつまずく文字コードと照合順序の話に移ります。
→ 次の記事:文字コード・照合順序(utf8mb4)でハマらないために
タグ: MySQL, 上級者向け, アーキテクチャ