第15回: クエリチューニングの手順 — 計測なき最適化は迷走する
「なんとなく遅そうだからインデックスを足した」——そのインデックスは本当に効いていましたか?感覚だけでクエリを変更すると、改善なのか改悪なのか判断できず、問題が複雑化します。クエリチューニングは「計測→仮説→検証」の順で進めることで、再現性のある改善ができます。
Month
「なんとなく遅そうだからインデックスを足した」——そのインデックスは本当に効いていましたか?感覚だけでクエリを変更すると、改善なのか改悪なのか判断できず、問題が複雑化します。クエリチューニングは「計測→仮説→検証」の順で進めることで、再現性のある改善ができます。
ユーザー一覧を表示するたびに、各ユーザーの投稿を個別に取得している——そんな実装を見たことはないでしょうか。これがN+1問題です。10件なら10回、1000件なら1001回のクエリが走り、データ量の増加とともに急激にレスポンスが悪化します。
体感でクエリを最適化しようとすると、改善なのか改悪なのか判断できません。EXPLAINを使えば、MySQLがどのようにクエリを実行しているかを数値で把握できます。この回ではEXPLAINの読み方を整理し、根拠ある改善ができるようになりましょう。
「インデックスを追加したはずなのに、クエリが遅い」——そんな経験はありませんか?実は複合インデックスは、列の順序を間違えるとほとんど機能しません。正しい順序で設計するだけで、クエリが劇的に速くなるケースがあります。この回では複合インデックスの順序の考え方を整理していきます。
テスト環境では一瞬だったクエリが、本番の数十万件データでは5秒以上かかる。そういう事態に直面したとき、「インデックスを貼ればいいんじゃないか」と感覚で対応するのは危険です。闇雲にインデックスを追加すると、INSERT/UPDATE のたびにインデックスの更新コストが増え、むしろ書…
サブクエリを多重にネストしたSQLは、どこが何を返しているのか追いにくく、バグの原因も特定しづらくなります。3段ネストのサブクエリは、書いた本人でも翌週には読めないことがあります。
WHERE postcount >= 10 と書きたくなりますが、postcount は集計結果なので WHERE の時点ではまだ存在しません。WHERE はグループ化・集計の前に評価されるため、集計後の値を条件にするには別の構文が必要です。
全投稿を取得してPHPの配列で count() するコードは、データが増えるほどメモリと処理時間を消費します。1万件のレコードを全件取得してアプリ側で集計するのは、DB本来の仕事をわざわざ横取りしている状態です。
投稿一覧を取得した後、各投稿の著者名を取るためにループで SELECT FROM users WHERE id = ? を繰り返す——これがN+1問題の典型例です。100件の投稿があれば101本のSQLが走り、データが増えるほどレスポンスが悪化します。
一覧画面でよくある失敗が「ORDER BYを書かずにLIMITだけ指定する」パターンです。ORDER BYなしのLIMITは、MySQLが内部でどの行を返すかを保証しないため、同じクエリでも実行するたびに結果の順番が変わるという不具合が起きます。さらに、データ量が増えると OFF…