発展原因を指せるようになる

Index Cond と Filter の違い(読む前に効く条件・読んだ後に捨てる条件)

定義

Index Cond はインデックスを辿る段階で使われる条件で、読む行数そのものを減らす。Filter は行を読んだ後に捨てるための条件で、読む量は減らない。Rows Removed by Filter がその無駄読みの量を示す。

同じ条件が、2 か所のどちらかに出る

WHERE に書いた条件は、実行計画ではIndex Cond 側か Filter 側かのどちらかに現れます。 この 2 つは効くタイミングが違います。

  • Index Cond — インデックスを辿る段階で使う。読む行数そのものが減る
  • Filter — 行を読んだあとに捨てる。読む量は減らない

同じクエリでも、インデックスの張り方でどちらに出るかが変わります。実際に並べます。

まず、2 つが並んで出ている計画を見る

id(主キー・インデックスあり)とgrade(インデックス無し)で絞ります。

SELECT * FROM members WHERE id BETWEEN 1000 AND 1200 AND grade = 'gold';
 Index Scan using members_pkey on members  (cost=0.42..14.26 rows=71 width=34) (actual time=0.012..0.028 rows=67.00 loops=1)
   Index Cond: ((id >= 1000) AND (id <= 1200))
   Filter: (grade = 'gold'::text)
   Rows Removed by Filter: 134
   Index Searches: 1
 Planning Time: 0.292 ms
 Execution Time: 0.054 ms

Index Cond と Filter が同じノードに並んで出ている。
PostgreSQL 18.6 / 2026-08-22 採取 / 並列・JIT は OFF

2 つが上下に並んでいます。

  • Index Cond: ((id >= 1000) AND (id <= 1200)) インデックスを辿る段階で使われた条件
  • Filter: (grade = 'gold') 行を読んでから判定した条件
  • Rows Removed by Filter: 134 — 201 行読んで134 行を捨てた(返したのは 67 行)

id の側はインデックスが範囲を直接絞れるので、そもそも 201 行しか読んでいません。grade の側はインデックスが無いので、201 行すべてを読んでから 134 行を捨てています。これが「読む前に効く」と「読んだあとに捨てる」の違いです。

スキャンの種類によって、条件の出る場所が変わります。上の Index Scan では Index Cond Filter が同じノードに並びますが、Bitmap Heap Scan になると Index Cond は 子ノードの側に移ります。次がその形です。

Bitmap になると、条件が 2 つのノードに分かれる

-- members(city) にだけインデックスがある
SELECT * FROM members WHERE city = 'city-7' AND grade = 'gold';
 Bitmap Heap Scan on members  (cost=113.01..4431.51 rows=3346 width=34) (actual time=0.697..9.094 rows=3333.00 loops=1)
   Recheck Cond: (city = 'city-7'::text)
   Filter: (grade = 'gold'::text)
   Rows Removed by Filter: 6667
   Heap Blocks: exact=4167
   ->  Bitmap Index Scan on members_city_idx  (cost=0.00..112.17 rows=10100 width=0) (actual time=0.417..0.417 rows=10000.00 loops=1)
         Index Cond: (city = 'city-7'::text)
         Index Searches: 1
 Planning Time: 0.202 ms
 Execution Time: 9.276 ms

Index Cond は子の Bitmap Index Scan 側にある。
PostgreSQL 18.6 / 2026-08-22 採取 / 並列・JIT は OFF

条件が 2 つのノードに散っています。探すときは子まで見てください。

  • 子の Bitmap Index Scan Index Cond: (city = 'city-7') これが本物の Index Cond。 インデックスを辿って「どのページを読むか」を決めている
  • 親の Bitmap Heap Scan Recheck Cond: (city = 'city-7') — 同じ条件をもう一度書いたもの。 ビットマップが粗くなったときに備えた確認用で、「読む前に効いている」側という点は Index Cond と同じ
  • Filter: (grade = 'gold') Rows Removed by Filter: 6667 — こちらは変わらず読んだあとに捨てている

10,000 行読んで 3,333 行しか使っていません。3 分の 2 が無駄読みです。

両方を含む複合インデックスを張ると

CREATE INDEX members_city_grade_idx ON members (city, grade);
 Bitmap Heap Scan on members  (cost=47.00..4234.56 rows=3373 width=34) (actual time=0.452..3.415 rows=3333.00 loops=1)
   Recheck Cond: ((city = 'city-7'::text) AND (grade = 'gold'::text))
   Heap Blocks: exact=3333
   ->  Bitmap Index Scan on members_city_grade_idx  (cost=0.00..46.15 rows=3373 width=0) (actual time=0.242..0.243 rows=3333.00 loops=1)
         Index Cond: ((city = 'city-7'::text) AND (grade = 'gold'::text))
         Index Searches: 1
 Planning Time: 0.237 ms
 Execution Time: 3.518 ms

Filter が消え、両方の条件が読む前に効くようになった。
PostgreSQL 18.6 / 2026-08-22 採取 / 並列・JIT は OFF

Filter の行が消えました。代わりにRecheck Cond(と子の Index Cond)に両方の条件が乗っています。Rows Removed by Filter も出ていません。捨てる行がゼロになったということです。

効果は Heap Blocks の行に出ています。これは実際に読んだページ数です。

  • 単一インデックス: Heap Blocks: exact=4167
  • 複合インデックス: Heap Blocks: exact=3333

4,167 ページ → 3,333 ページ。20% 減りました。捨てる行が無くなったぶん、触るページも減っています。

読む量が減った結果は、実行時間にも出ています。同じ計画の Execution Time 9.3 ミリ秒 → 3.5 ミリ秒(2.6 倍)。 ページを 20% 減らしただけに見えて、行を捨てる処理そのものが無くなっているぶん差が大きく出ます。 複合インデックスの列順の話は複合インデックスに。

3 つを並べると、捨てている量の差が見える

読んだ行のうち、何行を捨てているか
Index Scan読んだ 201 → 返した 67うち 134 を捨てた(67%)単一インデックス読んだ 10,000 → 返した 3,333うち 6,667 を捨てた(67%)複合インデックス読んだ 3,333 → 返した 3,333捨てた行なし返した行読んだのに捨てた行(Rows Removed by Filter)
薄い部分が「読んだのに捨てた行」。Index Cond に乗せられた条件が増えるほどここが短くなり、 複合インデックスではゼロになる棒の長さはそろえてあるので、比べているのは行数ではなく捨てた割合。実際の行数は棒の右に出ている。

Rows Removed by Filter の読み方

この数字が「無駄読みの量」です。大きければ大きいほど、インデックスを見直す価値があります。

ただし絶対値では判断できません。1 万行捨てていても、それが全体の 1% なら気にする必要はありません。返した行数と並べて見ます。

  • 返した行 3,333 / 捨てた行 6,667 → 3 分の 2 が無駄。直す価値がある
  • 返した行 100 万 / 捨てた行 1,000 → 気にしなくてよい

ループの内側に出ることもあります。遅いノードの見つけ方の題材では、 内側のノードに Rows Removed by Filter: 4 が出ています。1 回あたり 4 行という意味なので、loops を掛けると 100 万行捨てていることになります。loops が付いているときは、この数字も 1 回あたりです。

インデックスが効いているかの判定にも使える

「インデックスを貼ったのに速くならない」ときは、まず条件が Index Cond 側に乗っているかを見ます。Filter 側に残っていれば、そのインデックスはその条件には効いていません。

乗らない理由はいくつもあります(列に関数をかけている、型が合っていない、 複合インデックスの左端を使っていない、など)。 一覧はインデックスが使われないときに何を見るかに まとまっています。

よくある疑問

Q.Filter が出ていたら必ず直すべきですか?
A.直す価値があるかは Rows Removed by Filter の大きさで決めます。捨てている行が少なければ、インデックスを増やすコストの方が高くつきます。
Q.Recheck Cond は Filter とは違うのですか?
A.違います。Recheck Cond は Bitmap Heap Scan がビットマップを粗く持ったときに、行を読んでから条件をもう一度確かめるためのものです。インデックスで絞れている点は Index Cond と同じです。
Q.Rows Removed by Filter が 0 なのに Filter が出ています
A.条件は評価されているが、たまたま 1 行も捨てなかったという意味です。条件を満たさない行が増えれば捨て始めます。

関連トピック

もっと学びたい方へ(おすすめ書籍)

SQL実践入門 ── 高速でわかりやすいクエリの書き方
ミック

「なぜこの書き方が速いのか」を実行計画から説明する一冊。条件分岐・集約・結合・更新のそれぞれで、良い書き方と悪い書き方を対比しながら読める。

Amazon で見る →
おすすめ
達人に学ぶDB設計徹底指南書 第2版
ミック

テーブル設計と正規化、パフォーマンス考慮のインデックス設計まで実務レベルで学べる定番書。第2版ではクラウド対応も強化。

Amazon で見る →
おすすめ
楽々ERDレッスン (CodeZine BOOKS)
羽生章洋

ER 図をどう「使える設計」に落とすか、実務の判断まで踏み込んだ入門書。エンティティの切り出しから多対多の扱いまで具体例が豊富。

Amazon で見る →
おすすめ
スッキリわかるSQL入門 第4版 ドリル256問付き!
中山清喬/飯田理恵子

ドリル 256 問を実際に打ちながら進める SQL の入門書。付属のブラウザ環境で演習できるので、SELECT から結合・集約までを環境構築で止まらずに通せる。

Amazon で見る →
達人に学ぶSQL徹底指南書 第2版
ミック

SQLの本質的な使い方と、インデックスが効くクエリの書き方を学べる。ウィンドウ関数など現代SQLも網羅。

Amazon で見る →
SQLアンチパターン 第2版
Bill Karwin

実務でやりがちなSQL・DB設計のアンチパターンとその回避策を体系的に学べる。

Amazon で見る →
[改訂3版]内部構造から学ぶPostgreSQL
勝俣智成 ほか

PostgreSQLの内部構造・ストレージ・インデックス機構を丁寧に解説。設計と運用計画の鉄則が学べる。

Amazon で見る →
情報処理教科書 データベーススペシャリスト 2025年版
三好康之

IPAデータベーススペシャリスト試験の総合対策書。インデックス関連は本サイトと合わせて学ぶと理解が深まる。

Amazon で見る →
理論から学ぶデータベース実践入門
奥野幹也

リレーショナルモデルの理論から、インデックス設計を含む実務で使えるSQLまで解説。

Amazon で見る →

本セクションはAmazonアソシエイトのリンクを含みます。

オンライン個別指導

もっと深くDBを学びたい方へ。

たいてっくが、SQL・データベース設計・パフォーマンスチューニング・IPAデータベーススペシャリスト対策まで、1対1で学習をサポートします。まずは無料相談から。

無料相談を予約する →
受講者の声 (DB・SQL コース)
menta レビュー原文を見る →
  • 教え方も上手で、お人柄も良いメンターです。DB周りの知識はもちろん、何より、しっかり教えてあげようという姿勢がとてもありがたかったです。データベース、SQLの学習を考えている方にはおススメです。
    H 様DB・SQL コース受講
  • 体系的に知識を教えてくださり、実際の業務でも大変役立っております。特に短い時間で効率よく知識の習得や、練習をできているのは期待以上でした。
    M 様DB・SQL コース受講
  • 大変充実したコンテンツでわかりやすいご説明をありがとうございました。基本的な質問にも丁寧にご説明いただき、また業務のご相談にも乗って頂き大変有意義な時間でした。
    K 様DB・SQL コース受講