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

スキャンの種類(Seq / Index / Index Only / Bitmap)

定義

Seq Scan はテーブルを先頭から読む方法、Index Scan はインデックスを辿って 1 行ずつ取りに行く方法、Index Only Scan はインデックスだけで完結してテーブルを読まない方法、Bitmap Heap Scan は該当する行の位置をいったんビットマップに集めてからページ順にまとめて読む方法である。

4 つの表記

テーブルからデータを取り出すノードには 4 つの顔があります。どれが出ているかで、何をしているかが分かります。

先に用語を 1 つ。この先に出てくる HeapBitmap Heap Scan /Heap Blocks / Heap Fetches)はテーブル本体のことです。インデックスと区別するための呼び名で、「Heap を読んだ」=「テーブル本体を読んだ」と読み替えて構いません。

Seq Scan — 先頭から最後まで読む

Seq Scan — 先頭から最後まで、順に読む
テーブル(8 ページ)12345678左から右へ、1 回のまとまった読み取り

が条件に合う行。読んだページ: 8 / 8(該当行が 2 ページ分でも、全部読む)

インデックスを見ないので、どのページに該当行があるか分からない。 だから全部読んで、読んでから条件で捨てる。ページを順に読むので 1 ページあたりは速い。
 Seq Scan on members  (cost=0.00..10417.00 rows=500000 width=34) (actual time=0.006..22.839 rows=500000.00 loops=1)
   Filter: (age >= 20)
   Rows Removed by Filter: 0
 Planning Time: 0.145 ms
 Execution Time: 33.422 ms

50 万行を全部読む。
PostgreSQL 18.6 / 2026-08-22 採取 / 並列・JIT は OFF

テーブルを順番に全部読みます。インデックスが使えないとき、あるいは使わない方が速いと判断されたときに選ばれます。

Index Scan — インデックスを辿って 1 行ずつ取りに行く

Index Scan — 1 件見つけるたびに、そのページへ飛ぶ
インデックス(キー順に並んでいる)k=12k=34k=561 回目2 回目3 回目テーブル(8 ページ)123456783 ページ目 → 7 ページ目 → 3 ページ目。行ったり来たりしている

が条件に合う行。読んだページ: 3 回(3 ページ目を 2 回読んでいる)

インデックスはキー順に並んでいるので、飛び先のページ順はバラバラになる。 同じページに何度も戻ることもある。該当行が増えるほど、この往復が増える。
 Index Scan using members_pkey on members  (cost=0.42..8.44 rows=1 width=34) (actual time=0.015..0.016 rows=1.00 loops=1)
   Index Cond: (id = 42)
   Index Searches: 1
 Planning Time: 0.253 ms
 Execution Time: 0.046 ms

主キーで 1 行だけ引く。
PostgreSQL 18.6 / 2026-08-22 採取 / 並列・JIT は OFF

Index Cond: に条件が乗っているのが目印です。 インデックスで場所を特定してから、その行があるページを読みに行きます。

該当行が多いと不利になります。行ごとにページをバラバラに読むことになるためです。

Index Only Scan — テーブルを読まない

Index Only Scan — テーブルを 1 回も読まない
インデックス(キー順に並んでいる)k=12+ 東京k=34+ 大阪k=56+ 福岡値まで入っているテーブルへは行かないテーブル(8 ページ)12345678Heap Fetches: 0 が「1 回も触っていない」印

が条件に合う行。読んだページ: 0(必要な値がインデックスに入っている)

欲しい列が全部インデックスに入っているときだけ選ばれる。 テーブル本体へ行かないので、いちばん速い形。 これを狙って作るのがカバリングインデックス。
SELECT city FROM members WHERE city = 'city-7';

取り出すのが city だけで、 その city にインデックスが張ってあります。欲しい値がインデックスの中に全部あるので、テーブル本体に用がありません。

 Index Only Scan using members_city_idx on members  (cost=0.42..213.17 rows=10100 width=7) (actual time=0.032..0.435 rows=10000.00 loops=1)
   Index Cond: (city = 'city-7'::text)
   Heap Fetches: 0
   Index Searches: 1
 Planning Time: 0.278 ms
 Execution Time: 0.689 ms

Heap Fetches: 0。テーブル本体を 1 回も触っていない。
PostgreSQL 18.6 / 2026-08-22 採取 / 並列・JIT は OFF

必要な列が全部インデックスに入っているときだけ選ばれます。 テーブル本体を読まないので、いちばん速い形です。Heap Fetches: 0 が「1 回も触っていない」印です。

これを狙って作るのがカバリングインデックスです。遅いノードの見つけ方では、 実際にこれで内側を 5 分の 1 にしています。

Bitmap Heap Scan — 位置を集めてから、まとめて読む

Bitmap Heap Scan — 位置を集めてから、ページ順に読む
インデックス(キー順に並んでいる)k=12k=34k=561. 該当ページを集める(ビットマップ)001000102. 立っているページだけを、左から右へ 1 回ずつ読むテーブル(8 ページ)12345678同じページへ 2 回行っていたのが 1 回になった

が条件に合う行。読んだページ: 2(重複が消え、左から右へ 1 回ずつ)

飛び先をいったんページ単位で集めてから読むので、 往復と重複が消える。減っているのは往復の回数で、 該当行がテーブル全体に散らばっていれば読むページ数自体は減らない
 Bitmap Heap Scan on members  (cost=114.70..4407.95 rows=10100 width=34) (actual time=0.815..5.297 rows=10000.00 loops=1)
   Recheck Cond: (city = 'city-7'::text)
   Heap Blocks: exact=4167
   ->  Bitmap Index Scan on members_city_idx  (cost=0.00..112.17 rows=10100 width=0) (actual time=0.507..0.507 rows=10000.00 loops=1)
         Index Cond: (city = 'city-7'::text)
         Index Searches: 1
 Planning Time: 0.209 ms
 Execution Time: 5.571 ms

Bitmap Index Scan で位置を集め、Bitmap Heap Scan でページ順に読む。
PostgreSQL 18.6 / 2026-08-22 採取 / 並列・JIT は OFF

2 段構えになっているのが特徴です。

  1. Bitmap Index Scan がインデックスを辿って、該当行の位置だけを集める
  2. Bitmap Heap Scan が、集めた位置をページ順に並べ替えて読む

Index Scan がインデックスを引くたびにテーブルへ飛ぶのに対して、先に位置を全部集めてから、ページ順にまとめて読むのが違いです。 該当行が「そこそこ多い」ときに選ばれます。

ここで Heap Blocks: exact=4167 の意味を確かめてください。これは実際に読んだページ数です。この例が返しているのは 50 万行のうち 1 万行(2%)だけなのに、読んだページ数は 4,167 ページ —— 上の Seq Scan がテーブル全体を読んだのと同じ数です。

Bitmap は「読むページを減らす」方式ではありません。city の値がテーブル全体に散らばっているので、結局どのページにも 1 行以上入っているからです。 Bitmap が減らしているのはページを行き来する回数で、読む順番を整える方式だと考えるのが正確です。

ページ数まで減るのは、該当行が固まって置かれているときです。 行の物理的な並びがインデックス順にどれだけ近いかで効果が変わります(クラスタ化インデックス)。

Recheck Cond: が出るのは、 ビットマップが粗くなったときにページ単位で持つことがあり、 そのとき行を読んでから条件をもう一度確かめるためです。 この行の読み方はIndex Cond と Filter の違いに。

何 % を超えると全表スキャンになるか

実際に測りました。50 万行のテーブルで、条件に合う行の割合を少しずつ上げていきます。

条件見積り行数全体比選ばれたスキャン
age < 218,6832%Bitmap Heap Scan
age < 2541,1008%Bitmap Heap Scan
age < 3083,63317%Bitmap Heap Scan
age < 40165,40033%Bitmap Heap Scan
age < 45207,80042%Bitmap Heap Scan
age < 50250,55050%Bitmap Heap Scan
age < 52267,08353%Seq Scan
age < 55292,93359%Seq Scan
age < 60334,51767%Seq Scan
age < 80500,000100%Seq Scan

50% 前後で切り替わりました。250,550 行(50.1%)までは Bitmap Heap Scan267,083 行(53.4%)から Seq Scan です。

つまり「インデックスがあるのに Seq Scan になっている」のは、 たいてい正しい判断です。半分読むなら順に読んだ方が速いからです。

この境目は環境で動きます。バラバラに読む手間を順に読む手間の何倍と仮定するか、という設定値が効くためです。 既定では 4 倍と仮定していますが、SSD ではもっと近く、 キャッシュがよく効いていればさらに近くなります。「何 % で切り替わるか」を暗記するのではなく、 自分の環境で測るのが正しい向き合い方です。

インデックスがあるのに使われないとき

ここまでは「対象行が多いから使わない」という正しいケースでした。 それ以外の理由で使われないことも多くあります。 列に関数をかけた、型が合っていない、複合インデックスの左端を使っていない、など。

そちらはインデックスが使われないときに何を見るかに まとまっています。

よくある疑問

Q.Seq Scan が出たらインデックスを貼るべきですか?
A.そうとは限りません。対象行が全体の半分を超えるようなクエリでは、インデックスを辿るより順に読んだ方が速いのでプランナは正しく Seq Scan を選んでいます。このページの実測では 50% 前後が境目でした。
Q.Bitmap Heap Scan は何のためにあるのですか?
A.インデックスを辿って行を 1 件ずつ取りに行くと、ページをバラバラに読むことになります。該当行の位置をいったん集めてページ順に並べ替えてから読めば、まとめて読めるぶん速くなります。その中間的な方式です。
Q.Index Only Scan の Heap Fetches が 0 でないのはなぜですか?
A.インデックスだけでは行が見えてよいかを判断できない場合があり、そのときはテーブル本体を確認しに行きます。VACUUM が行き届いていると 0 に近づきます。

関連トピック

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

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

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

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 で見る →
情報処理教科書 データベーススペシャリスト 2025年版
三好康之

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

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

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

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

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

Amazon で見る →

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

オンライン個別指導

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

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

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