9.

パフォーマンスチューニング関連

編集

本稿は MySQL / MariaDB のパフォーマンスチューニングに関する記事です。クエリレベル・スキーマレベル・サーバ設定レベルで「どこから手を付けるか」の入口になります。

子ページから項目を選択してください。

本ページの子ページ

チューニングの階層

レイヤ主な打ち手効果の出やすさ
SQL / インデックスクエリ書き換え・索引追加・JOIN 順非常に高い (まずここから)
スキーマ型の選定・正規化/非正規化・パーティショニング高い (設計時に決めるのが理想)
サーバ設定 (my.cnf)バッファプール・接続数・ログ設定中程度 (典型値で十分なことも多い)
OS / ハードウェアSSD・メモリ増設・I/O スケジューラ状況依存
アプリ側N+1 解消・キャッシュ・バッチ化非常に高い

1. まず確認するコマンド

-- 実行計画を見る
EXPLAIN SELECT ...;
EXPLAIN ANALYZE SELECT ...;  -- MySQL 8.0+ / MariaDB 10.1+

-- テーブル定義・インデックス
SHOW CREATE TABLE t;
SHOW INDEX FROM t;

-- ステータス・統計
SHOW ENGINE INNODB STATUS\G
SHOW GLOBAL STATUS LIKE 'Innodb%';
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;

-- 遅いクエリ
SHOW VARIABLES LIKE 'slow_query_log%';

2. インデックスの基本

  • WHERE / JOIN ON で使う列にインデックスを張る
  • 選択性 (ユニーク度) の高い列ほど効きやすい
  • 複合インデックスは「等価条件+範囲条件」の順で並べる (例: (user_id, created_at))
  • カバリングインデックス: SELECT する全列を含むインデックスにして表アクセスを省く
  • 逆効果になりやすい例: 関数で包む (WHERE DATE(t) = ?)、左辺で計算する (WHERE col + 1 = ?)、暗黙の型変換

3. EXPLAIN の見どころ

注目ポイント
typeconsteq_refrefrangeindexALLALL はフルスキャン、避けたい
key実際に使われたインデックス。NULLなら未使用
rows処理見込み行数。大きすぎる場合は要絞り込み
ExtraUsing filesortUsing temporaryUsing where
filteredWHERE 後に残る割合 (%)。低いほど効率良く絞れている

4. クエリ書き換えの定番

  • SELECT * を避ける: 必要列のみ取得
  • LIMIT + OFFSET 大量はキーセットページング (WHERE id > ?) に変更
  • OR より UNION ALL: 複数のインデックスを使いたい場合
  • サブクエリ → JOIN: 多くの場合 JOIN のほうが最適化しやすい
  • LIKE '%xxx%' はインデックスが効かない。前方一致 ('xxx%') なら効く。本格的な全文検索なら FULLTEXT または外部全文検索エンジン
  • 大量更新は分割: LIMIT 1000 単位で UPDATE / DELETE

5. サーバ設定 (my.cnf) の重要パラメータ

パラメータ役割
innodb_buffer_pool_sizeInnoDB のメモリキャッシュ。データ全体が乗るのが理想 (空きメモリの 50〜70%)
innodb_log_file_sizeREDOログサイズ。大きいほど書き込み性能◎だがクラッシュ復旧は長くなる
innodb_flush_log_at_trx_commit1=安全 / 2=性能 / 0=性能最重視 (耐障害性は下がる)
max_connections最大同時接続数
tmp_table_size / max_heap_table_size一時テーブルがメモリに収まる上限
slow_query_log / long_query_time遅いクエリログ収集
query_cache_*MySQL 8.0 で削除済み。MariaDB は残るが基本オフ推奨

6. スキーマ設計の観点

  • 適切な型: BIGINT 不要なら INTVARCHAR(255) 一律ではなく必要長
  • NULL の最小化: NULL 演算は最適化が難しい場面がある
  • InnoDB が標準: トランザクション・行ロック
  • 主キーは短く、単調増加するもの (典型は AUTO_INCREMENT)
  • パーティショニング: 大量データはレンジ (日付) で分割。索引ローカルに注意

7. アプリ側でやれること

  • N+1 問題の解消 (ORM の eager loading / IN クエリ統合)
  • キャッシュ (Redis / Memcached) で読み込み負荷を退避
  • バッチ INSERT: 1件ずつ INSERT せず INSERT ... VALUES (...), (...), ...
  • 非同期化: 重い処理はキュー (Sidekiq / Worker) へ
  • レプリカ分離: 参照クエリは Read レプリカへ振る

注意点

  • 本番のチューニングは必ずバックアップ&検証環境で確認してから
  • パラメータ変更は1つずつ・効果を計測。一度に複数変えると原因切り分け不能
  • SHOW PROCESSLIST のロック待ちチェックは即効性のある調査手段
  • OS のスワップが発生していないか (vmstatfree) を確認。スワップは致命的

関連

編集
Post Share
子ページ
  1. 実行計画の出力
  2. テーブルに紐づくインデックスを確認する方法
同階層のページ
  1. ダウンロード&インストール方法(Windows)
  2. インストール方法(Linux)
  3. コマンド一覧
  4. SQL
  5. データ型
  6. 関数
  7. 管理ツール
  8. 設定
  9. パフォーマンスチューニング関連
  10. エクスポートおよびインポート
  11. エラー&トラブル
  12. 文字コードの確認
  13. 実行中の SQL の状態確認およびプロセスキルの方法
  14. パスワードの無効化設定
  15. root ユーザーの初期パスワード確認方法
  16. rootユーザーのパスワード変更方法
  17. LIMIT, OFFSET の始まりと挙動
  18. mysqlのバージョン確認方法
  19. 実行計画の表示方法
  20. レプリケーションのステータス確認方法
  21. 中央値の導き方(バージョン8未満)
  22. 階層SQL(バージョン8未満)
  23. パーセンタイルの導き方
  24. 特定スキーマの全テーブルの全カラム情報を取得する方法
  25. MySQLで文字列の置換をする方法