オプティマイザは別物?MySQLバージョン差の罠

オプティマイザはMySQLのバージョンごとに別物

MySQLをバージョンアップしたら、アプリは動いているのに急に遅くなった。
SQLもインデックスも変えていないのに、特定の画面だけ数十秒かかる。

この現象、実は珍しくありません。

そして原因の多くは、ストレージでもCPUでもありません。
オプティマイザが変わったことです。

MySQLはバージョンごとに機能が追加されますが、最も影響が大きいのはSQL機能ではなく「実行計画を決めるアルゴリズム」です。
つまりMySQLのバージョンアップとは、別のデータベースに近い挙動の変化を含みます。

オプティマイザとは何をしているのか

MySQLのオプティマイザ(optimizer)は、SQLをどう実行するかを決める頭脳です。

SQLは「何を取得したいか」しか書いていません。

SELECT *
FROM orders
WHERE created_at >= '2025-01-01';

このときMySQLは次を判断します。

  • どのインデックスを使うか
  • フルスキャンするか
  • JOIN順序はどうするか
  • 一時テーブルを使うか
  • ソート方法は何か

つまりSQLの性能は、SQL文そのものよりオプティマイザの判断に依存します。

バージョンごとに何が変わるのか

MySQLのアップデートでは、オプティマイザが継続的に改良されています。
ここが重要です。

多くの人は「速くなる」と考えます。
しかし実際は「判断基準が変わる」です。

例えば以下の変更が行われてきました。

  • 統計情報の扱い
  • インデックス選択のコスト計算
  • JOIN順序の探索方法
  • サブクエリの最適化
  • 派生テーブルの扱い
  • Hash Join の導入(8.0系)

つまり同じSQLでも、選択される実行計画が別物になります。

実際に起きる典型的な問題

もっとも多いのは「遅くなった」です。

例としてJOINを見ます。

SELECT *
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active';

あるバージョンでは users を先に絞り込み、少数の行に対して orders を参照します。
しかし別のバージョンでは orders を先に読み、そこから users を参照する計画を選ぶことがあります。

SQLは同じでも、読み込む行数が100倍以上変わります。
結果として、アプリ側から見ると「突然遅くなった」ように見えます。

これはバグではありません。
オプティマイザの「より正しい推定」の結果です。

なぜ開発環境では起きないのか

ここがさらに厄介です。

開発環境では再現しないことが多いです。

理由は単純で、データ量と分布が違うからです。

  • 開発環境:件数が少ない、均一
  • 本番環境:件数が多い、偏りがある

オプティマイザは統計情報からコストを計算します。
本番の分布では誤差が大きくなり、別の実行計画が選ばれます。

そのため、バージョンアップ後に本番だけ遅くなります。

バージョンアップ時の危険な思い込み

よくある思い込みがあります。

「テストが通ったから大丈夫」

これは機能テストの話です。
オプティマイザの問題は機能ではなく性能です。

しかも、全SQLを網羅的に検証するのは現実的ではありません。
実際には、運用後に初めて問題のSQLが使われて発覚します。

対策:必ず見るべきもの

バージョンアップ時に重要なのは、アプリの画面ではありません。
実行計画の差分です。

最低限、重要なクエリで確認します。

EXPLAIN FORMAT=JSON SELECT ...;

旧バージョンと新バージョンで

  • 使用インデックス
  • 予測行数
  • JOIN順序

が変わっていないかを確認します。

ここを見ずに本番移行すると、リリース後に性能障害として発覚します。

ヒント固定は最終手段

遅くなったSQLに対し、インデックスヒントを入れて固定することがあります。

SELECT /*+ INDEX(users idx_status) */ *
FROM users
WHERE status = 'active';

これは有効なこともあります。
しかし注意点があります。

データ分布が変わると、そのヒントが最適でなくなる可能性があります。
また次のバージョンで逆効果になる場合もあります。

ヒントは恒久対策ではなく、回避策です。

バージョンアップの現実的な向き合い方

MySQLのバージョンアップは、アプリの互換性よりもオプティマイザ互換性の問題が大きいです。

SQLが動くかどうかではなく、
「同じ速さで動くか」を確認する必要があります。

性能問題はリリース直後には気づきにくく、アクセス増加後に顕在化します。
そのため、バージョンアップの検証では成功条件を「エラーが出ない」にしない方が安全です。

MySQLは単なる保存エンジンではありません。
実行計画を選択する判断システムです。

そしてバージョンが変わるということは、その判断基準が変わるという意味です。
アップデートとは、機能追加よりも「考え方の変更」に近い作業だと理解すると、トラブルの予測がしやすくなります。