コンテンツにスキップ

AI Session Notes - 2026-03-23

MySQL Online DDL の実行時間予測と実行戦略

学んだこと

  • EXPLAIN は DML(SELECT/INSERT/UPDATE/DELETE)専用であり、DDL(ALTER TABLE 等)には使えない
  • Online DDL の実行時間は、テーブルサイズ・DDL の種類・I/O 性能・同時ワークロード・インデックス数など複数要因に依存するため、正確な事前予測は困難
  • 実行時間の見積もりには、ステージング環境での実測が最も信頼性が高い

詳細

DDL アルゴリズムの3分類(MySQL)

アルゴリズム 挙動 速度
INSTANT(MySQL 8.0+) メタデータのみ変更 ミリ秒単位 カラム末尾追加、デフォルト値変更
INPLACE テーブル再構築するが DML 非ブロック データ量に比例 インデックス追加、一部の型変更
COPY 新テーブルにコピー→差し替え 最も遅い 互換性のない型変更、文字コード変更

実行時間の見積もり方法

  1. information_schema.tables でテーブルサイズ(行数・データサイズ・インデックスサイズ)を確認
  2. ステージング環境で同等データ量のテーブルに対して ALTER を実測
  3. pt-online-schema-change(Percona)や gh-ost(GitHub)を使えば、進捗表示と推定残り時間が得られる
  4. performance_schema.events_stages_current で ALTER 実行中の進捗をリアルタイム確認可能
-- 進捗モニタリング
SELECT
  EVENT_NAME,
  WORK_COMPLETED,
  WORK_ESTIMATED,
  ROUND(WORK_COMPLETED / WORK_ESTIMATED * 100, 1) AS pct
FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE '%alter%';

中規模テーブル(数百万行)への複合インデックス追加戦略

学んだこと

  • 500万行程度のテーブルへのインデックス追加は、素の Online DDL(ALGORITHM=INPLACE, LOCK=NONE)で数分以内に完了するケースが多い
  • ALGORITHM=INPLACE, LOCK=NONE を明示的に指定すると、INPLACE 不可時にエラーで停止してくれるため安全
  • pt-online-schema-changegh-ost は数千万〜億行規模や、書き込みが常に多い環境で本領を発揮する
  • 複合インデックスのカラム順は、WHERE 句の等値条件カラムを先頭に、ORDER BY カラムを末尾に配置するのが基本

詳細

-- 明示的にアルゴリズムとロックを指定して安全に実行
ALTER TABLE your_table
  ADD INDEX idx_col1_col2 (col1, col2),
  ALGORITHM=INPLACE,
  LOCK=NONE;

実行前の確認事項:

  1. information_schema.tables でテーブルサイズと既存インデックス数を確認
  2. information_schema.innodb_trx で長時間実行中のトランザクションがないことを確認
  3. 可能ならトラフィックの少ない時間帯に実行

lock_wait_timeout によるメタデータロック待ちの回避

学んだこと

  • ALTER TABLE は開始時と完了時に短時間のメタデータロック(MDL)を取得する必要がある
  • 長いトランザクションが MDL を掴んでいると、ALTER が待ち状態になり、さらに後続の全クエリが連鎖的にブロックされる(これが最大のリスク)
  • lock_wait_timeout をセッション単位で短く設定することで、MDL 取得に失敗した場合に即座にエラー終了させ、連鎖ブロックを防げる
  • MDL が必要なのは ALTER の開始時と完了時の一瞬だけであり、INPLACE 処理中は DML をブロックしない

詳細

-- セッション単位で3秒に設定(デフォルトは1年)
SET SESSION lock_wait_timeout = 3;

ALTER TABLE your_table
  ADD INDEX idx_col1_col2 (col1, col2),
  ALGORITHM=INPLACE, LOCK=NONE;

-- MDL が3秒以内に取れなければエラーで即終了
-- → タイミングを変えてリトライすればよい

注意点:

  • SET SESSION で設定すること(GLOBAL だと他セッションに影響)
  • 3〜5秒が実用的な値。短すぎると成功率が下がる
  • ALTER 完了時にも MDL 取得があるが、一瞬なので問題になることは稀

EXPLAIN 出力の読み方 — 注視すべきポイント

学んだこと

  • EXPLAIN の出力項目は多いが、最優先で見るべきは typerowsExtra の3つ
  • type: ALL(フルスキャン)が出たら最優先で対処。大量行テーブルでは致命的
  • JOIN がある場合、rows は掛け算で効いてくるため、各テーブルの rows を掛け合わせて全体のスキャン規模を把握する
  • ExtraUsing temporary; Using filesort が両方出たら改善の優先度が高い
  • 複合インデックスの活用度合いは key_len で判断できる(短い場合、途中のカラムまでしか使われていない)

詳細

type カラム(アクセスタイプ)の評価順

type 意味 評価
const 主キー/ユニークキーで1行特定 最速
eq_ref JOIN で主キー/ユニークキーで1行特定 良い
ref 非ユニークインデックスで複数行 良い
range インデックスの範囲スキャン 許容範囲
index インデックス全体をスキャン 注意
ALL テーブルフルスキャン 危険

Extra カラムの主要な値

Extra の値 意味 対応
Using index カバリングインデックスで完結 最高
Using where インデックスで絞った後にさらに WHERE で絞っている 普通
Using temporary 一時テーブル作成 改善検討
Using filesort ソートにインデックスが使えていない 改善検討

key_len による複合インデックスの活用度確認

-- インデックス: (user_id INT, status VARCHAR(20), created_at DATETIME)
-- key_len: 4   → user_id のみ使用
-- key_len: 86  → user_id + status まで使用
-- key_len: 91  → 全カラム使用

EXPLAIN チェックリスト

  1. typeALL になっていないか?
  2. rows が想定より多すぎないか?(JOIN なら掛け算で考える)
  3. ExtraUsing temporary / Using filesort が出ていないか?
  4. keyNULL になっていないか?
  5. 複合インデックスなら key_len で何カラム目まで使われているか?

参考リンク

メタ情報

  • ツール: Claude Code
  • 関連技術: MySQL, InnoDB, Online DDL, EXPLAIN, インデックス設計, lock_wait_timeout