【テクニカル・上級編】 シーケンシャルスキャン – PostgreSQL

「悪者」扱いされるシーケンシャルスキャンの真実 ― なぜPostgreSQLは全走査を選ぶのか

PostgreSQLのパフォーマンスチューニングをしていると、必ずと言っていいほど「Seq Scan(シーケンシャルスキャン)」という言葉が耳に入ってきます。開発現場では、`EXPLAIN`の結果を見て「ああ、Seq Scanが出ちゃってる。インデックスが効いていないからダメだ」と即座にインデックスを追加する……そんな光景を何度も見てきました。

しかし、熟練のエンジニアならもうお気づきでしょう。Seq Scanは決して「悪」ではありません。 むしろ、データベースが最適化を極めた結果として選んだ、最も効率的な戦略であることも多いのです。

今日は、PostgreSQLのコアアーキテクチャの視点から、なぜあえて「全読み」が選ばれるのか、そしてそれがパフォーマンストラブルに直結したとき、我々は何を疑うべきなのかを深掘りしてみましょう。

—

1. なぜ「全走査」が爆速になり得るのか

まず、PostgreSQLのストレージ構造である「ヒープ(Heap)」の話をしましょう。データは8KBのページ単位で管理されていますが、Seq Scanが強力なのは、「シーケンシャルI/Oの恩恵」をフルに受けられるからです。

現代のストレージ(特にNVMe SSDなど)において、ランダムI/OとシーケンシャルI/Oの速度差は依然として無視できません。インデックスを使ったIndex Scanは、ツリー構造を辿りながらランダムにページへアクセスするため、大量のデータを取得しようとすると、OSのページキャッシュ効率が極端に落ち、ディスクヘッド(HDDの場合)やコントローラーのオーバーヘッドが増大します。

一方で、Seq Scanは「テーブルの先頭から末尾まで一直線に読む」だけです。読み取りヘッドが暴れず、先読み(Read-ahead)機能が最大限に働く。小規模なテーブルならメモリに全部乗ってしまうため、インデックスを引く計算コストすら不要になります。PostgreSQLのプランナがSeq Scanを選ぶのは、多くの場合、「インデックス経由よりも、力技で一気読みしたほうが速い」と判断しているからに他なりません。

2. 「コスト」計算の裏側にある残酷な現実

プランナがSeq Scanを選ぶ基準は、単純に`random_page_cost`と`seq_page_cost`のバランスです。

  • `seq_page_cost` (デフォルト: 1.0)
  • `random_page_cost` (デフォルト: 4.0)

この比率を見てください。PostgreSQLは「ランダムアクセスはシーケンシャルの4倍コストがかかる」と見積もっています。しかし、最新の高速なSSD環境では、この比率が実態と乖離しているケースが多々あります。

もしあなたのシステムで、「明らかにインデックスを使うべきクエリなのにSeq Scanが走っている」なら、まずはここを疑ってください。`random_page_cost`を下げて(例えば1.1程度に)設定し直すだけで、プランナの挙動が劇的に改善することは珍しくありません。

3. パフォーマンストラブルの真犯人:Seq Scanの「その先」

それでもなお、Seq Scanがボトルネックになってクエリが遅延する場合、原因はスキャンそのものよりも「その周辺」にあることが多いです。

  • Visibility Map (VM) の活用不足

PostgreSQLは、テーブルの各ページが「すべての行が可視(Visible)」かどうかをVMで管理しています。Vacuumが適切に回っていないと、VMが更新されず、本来ならスキャンをスキップできるページまで律儀に読みに行くことになります。

  • 過剰なBloat(肥大化)

UPDATEやDELETEが頻発しているテーブルでは、死んだ行(Dead Tuples)がページ内に大量に残留します。Seq Scanは、これら「無駄な行」も含めてすべて読み込まなければなりません。スキャン速度が遅いのではなく、「読み込む必要のないゴミを大量に読み込んでいる」のが真因です。

  • 並列クエリのオーバーヘッド

最近のPostgreSQLはSeq ScanをParallel Workerで並列実行しますが、データ量が中途半端な場合、ワーカーの立ち上げや結果の集約コストが、シングルスレッドでの実行時間を上回ることがあります。

最後に:エンジニアとして持つべき視点

Seq Scanが出たとき、反射的にインデックスを貼るのではなく、まずはこう自問してみてください。

「このクエリは、本当にインデックスが必要なデータ量なのか?」
「テーブルの物理構造は、スキャンに耐えうる状態か(Vacuumは効いているか)?」

Seq Scanは、PostgreSQLというエンジンの基礎体力を測るリトマス試験紙のようなものです。それが遅いということは、インデックスの問題ではなく、ストレージのレイアウトやバキューム戦略といった「データベースの健康状態」が損なわれているサインかもしれません。

エンジニアリングの本質は、最適化の手段を増やすことではなく、何がボトルネックなのかを正しく見極める冷静さにあるはずです。皆さんの現場のPostgreSQLが、今日も軽快にフルスキャンをこなしていることを祈っています。

コメント

タイトルとURLをコピーしました