インデックスが使われないときに何を見るか
インデックスが使われているかは実行計画で判定できる。条件が Index Cond に乗っていれば読む前に効いており、Filter に残っていればテーブルを読んでから捨てている。使われない理由には、列への関数適用・暗黙の型変換・中間一致・複合インデックスの左端規則・対象行が多すぎる・統計が古いなどがある。
貼ったのに速くならない
インデックスは、貼れば必ず使われるわけではありません。使われているかどうかは実行計画を見れば分かり、 使われない理由はだいたい 8 つのどれかです。
実行計画そのものが読めない場合は先に実行計画の読み方へ。 このページは「読める」前提で、インデックス側の話だけをします。
判定は 1 行で済む
実行計画で、その条件がどちらに出ているかを見ます。
Index Cond:に乗っている → 使われている。 読む行数そのものが減っているFilter:に残っている → 使われていない。 テーブルを読んでから捨てている
Rows Removed by Filter が出ていれば、それが捨てた行数です。 この数字が返した行数に比べて大きければ、それだけ無駄に読んでいます。
表記の詳しい意味と、同じクエリで両方を見比べた実例はIndex Cond と Filter の違いに。
なお Index Scan ではなく Index Only Scan が出ていれば、テーブル本体を読まずに済んでいるという意味で、いちばん効いている状態です。 一意インデックスなら 1 行と分かった時点で探索が止まるので、 条件が等値のときは一意インデックスかどうかでも 読む量が変わります。
使われない 8 つの理由
1. 列に関数をかけている
WHERE lower(email) = 'a@example.com'
なぜ: インデックスは email の値で並んでいる。lower(email) の値では並んでいないので辿れない。
直し方: 式そのものにインデックスを作る(式インデックス)か、保存時に小文字で入れておく。 B-tree インデックス
2. 暗黙の型変換が入っている
WHERE zip_code = 1500001 -- zip_code は varchar
なぜ: 比較のために列側が数値へ変換される。変換後の値では並んでいないので辿れない。
直し方: 型を合わせる('1500001' と書く)。アプリ側から渡す値の型も確認する。 B-tree インデックス
3. 中間一致・後方一致で検索している
WHERE name LIKE '%tanaka'
なぜ: B-tree は先頭から順に並んでいるので、先頭が分からないと探し始められない。
直し方: 前方一致にできないか見直す。できないなら全文検索の索引を検討する。 B-tree インデックス
4. 複合インデックスの左端を使っていない
-- (city, grade) の索引に対して WHERE grade = 'gold'
なぜ: 複合インデックスは左の列から順に並んでいる。左端を指定しないと辿る起点が決まらない。
直し方: 列順を見直すか、使い方に合った索引を別に作る。 複合インデックス
5. OR でつないでいる
WHERE city = 'tokyo' OR grade = 'gold'
なぜ: どちらか片方でも当たれば対象になるので、片方の索引だけでは絞りきれない。
直し方: UNION に分ける。よく使う条件が固定なら部分インデックスも効く。 部分インデックス
6. ORDER BY の方向が索引と合っていない
-- (a ASC, b ASC) の索引に対して ORDER BY a ASC, b DESC
なぜ: 索引を順に辿れば並び替えずに済むはずが、方向が混ざると辿るだけでは順序が作れない。
直し方: その並び順に合わせた索引を作る(列ごとに方向を指定できる)。 B-tree インデックス
7. 対象行が多すぎて、読んだ方が速い
WHERE age < 55 -- 50 万行中 29 万行が該当
なぜ: 索引を辿ると行ごとにページをバラバラに読むことになる。半分読むなら順に読んだ方が速い。
直し方: 直す必要は無い。これはプランナが正しく判断している。 スキャンの種類(切り替わりの実測つき) / クラスタ化インデックス(行の並びで結果が変わる)
8. 統計が古い / 見積りが外れている
-- 大量投入の直後、ANALYZE 前
なぜ: 何行返るかの見積りが外れると、索引を使うかどうかの判断そのものが間違う。
直し方: ANALYZE を打つ。それでも直らないなら列どうしの相関を疑う。 遅いノードの見つけ方 / 統計情報とオプティマイザ
「使われていない」と「使わない方が速い」は違う
7 番は直す必要がありません。インデックスを辿ると行ごとにページをバラバラに読むことになるので、 対象行が多いときは順に全部読んだ方が速いためです。
実際に測ると、全体の 50% 前後で切り替わります。 50 万行のテーブルで、条件に合う行が 25 万行を超えたあたりから全表スキャンが選ばれます。 測定した表はスキャンの種類にあります。
「Seq Scan が出ているから遅い」ではありません。まず対象行の割合を見て、それから 1〜6 と 8 を当ててください。
貼る前に確かめる手順
EXPLAINを打つ。使われるかどうかは見積りの段階で決まるので、ANALYZEは無くても判定できます- 条件が
Index Cond側に乗るか見る - 乗らないなら、上の 8 つを上から当てる
- 貼ると決めたら、更新が遅くなる分も見積もる。インデックスの更新コストへ
- 必要な列を全部含められるならカバリングインデックスにすると、 テーブル本体を読まずに済みます
よくある勘違い
- 「インデックスを貼れば必ず速くなる」 — 7 番のとおり、 対象行が多ければ逆効果です。書き込みも遅くなります
- 「実行計画に索引名が出ていれば使われている」 —
Bitmap Index Scanは索引を使いますが、 そのあとテーブルも読みます。どれだけ読んだかはHeap Blocksに出ます - 「複合インデックスは列の順番と関係ない」 — 4 番のとおり、 左端から順に使われます
よくある疑問
関連トピック
もっと学びたい方へ(おすすめ書籍)
SQLの本質的な使い方と、インデックスが効くクエリの書き方を学べる。ウィンドウ関数など現代SQLも網羅。
IPAデータベーススペシャリスト試験の総合対策書。インデックス関連は本サイトと合わせて学ぶと理解が深まる。
「なぜこの書き方が速いのか」を実行計画から説明する一冊。条件分岐・集約・結合・更新のそれぞれで、良い書き方と悪い書き方を対比しながら読める。
テーブル設計と正規化、パフォーマンス考慮のインデックス設計まで実務レベルで学べる定番書。第2版ではクラウド対応も強化。
ER 図をどう「使える設計」に落とすか、実務の判断まで踏み込んだ入門書。エンティティの切り出しから多対多の扱いまで具体例が豊富。
ドリル 256 問を実際に打ちながら進める SQL の入門書。付属のブラウザ環境で演習できるので、SELECT から結合・集約までを環境構築で止まらずに通せる。
実務でやりがちなSQL・DB設計のアンチパターンとその回避策を体系的に学べる。
PostgreSQLの内部構造・ストレージ・インデックス機構を丁寧に解説。設計と運用計画の鉄則が学べる。
リレーショナルモデルの理論から、インデックス設計を含む実務で使えるSQLまで解説。
本セクションはAmazonアソシエイトのリンクを含みます。
もっと深くDBを学びたい方へ。
たいてっくが、SQL・データベース設計・パフォーマンスチューニング・IPAデータベーススペシャリスト対策まで、1対1で学習をサポートします。まずは無料相談から。
「教え方も上手で、お人柄も良いメンターです。DB周りの知識はもちろん、何より、しっかり教えてあげようという姿勢がとてもありがたかったです。データベース、SQLの学習を考えている方にはおススメです。」
— H 様(DB・SQL コース受講)「体系的に知識を教えてくださり、実際の業務でも大変役立っております。特に短い時間で効率よく知識の習得や、練習をできているのは期待以上でした。」
— M 様(DB・SQL コース受講)「大変充実したコンテンツでわかりやすいご説明をありがとうございました。基本的な質問にも丁寧にご説明いただき、また業務のご相談にも乗って頂き大変有意義な時間でした。」
— K 様(DB・SQL コース受講)