SQLチューニングの落とし穴:インデックスが効かない意外なケース
はじめに
SQLのパフォーマンス改善において、インデックスは非常に強力な武器です。しかし、「インデックスがあるのに遅い」という現象に遭遇したことはありませんか?
本記事では、ユーザーの入力パラメータによってインデックスの有無が実行計画に影響するケースについて解説します。
ケーススタディ:user_idでの絞り込み
例えば、動画配信サービスの視聴履歴テーブル WatchHistory
に対して、特定ユーザーの視聴回数をカウントする以下のSQLを考えてみます。
SELECT COUNT(*)
FROM WatchHistory
WHERE user_id = :uid;
このSQLは、あるユーザー(user_id
)がどれだけの動画を見たかを調べるものです。非常にシンプルな構文ですが、指定されるパラメータ :uid
の値によって、インデックスが使われたり、フルテーブルスキャンになったりするという現象が発生します。
パターン別の実行結果
パターン |
user_id に対応する視聴記録件数 |
実行プランの傾向 |
---|---|---|
一般ユーザー(例:10万件) | 少ない(低選択率) | インデックススキャン |
ヘビーユーザー(例:1,000万件) | 多い(高選択率) | フルテーブルスキャン |
インデックスは「絞り込み効果が高いとき」に威力を発揮します。しかし、大量の行が該当してしまう場合、インデックス経由でランダムアクセスするより、全件読み込んだ方が速いとDBMSが判断し、インデックスを使わずフルスキャンに切り替えることがあります。
問題点:入力パラメータに依存する性能変動
このような状況では、以下のような問題が起こります。
- 同じSQL文でも、入力値によって実行時間が極端に変わる
- テスト環境では高速でも、本番で遅くなる
- 特定のヘビーユーザーに偏ったアクセスがあるとシステム全体が重くなる
つまり、「パラメータ次第でインデックスが無効化されるリスク」が潜んでいるのです。
対策
こうした問題に対応するには、いくつかの方法があります。
-
EXPLAIN
やEXPLAIN ANALYZE
で実行計画を確認する - 統計情報を適切に更新しておく(ANALYZEなど)
- ユースケースに応じてヒント句(例:
USE INDEX
)を使う - ヘビーユーザーのデータを別テーブルやパーティションに分割する
- マテリアライズドビューやキャッシュの活用
まとめ
インデックスは万能ではありません。同じクエリでも、ユーザーが入力するパラメータによって実行計画が大きく変わることがあります。とくに、選択率が高い値が入力された場合、インデックスが無視され、フルスキャンになることがある点には注意が必要です。
SQLチューニングでは、「実際にどの値が使われるか?」を意識して、現実的なケースでの実行計画をチェックすることが重要です。
参考
- 書籍:『達人に学ぶ SQL徹底指南書』(ミック著)