Index の設計と検証
Default — query から考える
Section titled “Default — query から考える”注文一覧を customer_id で絞り、created_at の新しい順に 20 件返すとする。
まず実際の query、行数、データ分布と実行計画を確認し、
(customer_id, created_at DESC) の B-tree index を候補にする。
列ごとに機械的に index を作るのではなく、絞り込みと並び順の組合せから考える。
Why — 調べる範囲と sort を減らす
Section titled “Why — 調べる範囲と sort を減らす”B-tree は順序を持つ。先頭列の等価条件で範囲を狭め、続く列の順序を利用できる場合がある。 この query では必要な 20 件を早く取得できることを期待するが、採用される plan は統計や分布に依存する。 詳しくは PostgreSQL 18: Multicolumn Indexes。
図はアプリと DB のやり取りを示す概念図で、PostgreSQL 内部処理や実測 latency を示すものではない。 図の操作 UI は英語。
Trade-off — 書き込みと容量
Section titled “Trade-off — 書き込みと容量”index は追加の容量を使い、データ変更時に保守が必要になる。 読み取りの短縮と、書き込み・運用への影響を両方検証する。 公式 Introductionを参照。
Exception — Seq Scan は必ずしも悪くない
Section titled “Exception — Seq Scan は必ずしも悪くない”大部分の行を読む場合や小さいテーブルでは、全体を順に読む方が有利な場合がある。 「index があれば必ず速い」「複合 index の後続列だけでは絶対に使えない」とは言わない。 PostgreSQL 18 には条件次第で skip scan を利用する場合もある。まず実行計画で確かめる。
Apply — 同じ query を比較する
Section titled “Apply — 同じ query を比較する”リポジトリのターミナルで実行する。Docker Desktop を起動しておく。
npm run db:upnpm run db:lablabs/database-index.sql は専用の index_lab schema に 10 万件の合成データを作り、
同じ SELECT を index 追加前後に実行する。再実行するとこの schema だけを作り直す。
記録するもの:scan の種類、推定行数と実測行数、sort の有無、Buffers、実行時間。
EXPLAIN ANALYZE は SQL を実際に実行する。今回は学習用 DB の SELECT を対象にしている。
時間の一回比較だけで結論を出さず、cache が温まる影響も考える。
Using EXPLAINで出力の意味を確認する。
Production — 利用者の遅さから観測する
Section titled “Production — 利用者の遅さから観測する”一覧 API の p99 とエラー率を起点に、query の時間、待機、接続待ち、DB とアプリのメトリクスを関連付ける。 index 作成時の lock や I/O、書き込み負荷も検討対象。学習用の CREATE INDEX を本番へそのまま流用しない。
Troubleshooting — 次に何を確かめるか
Section titled “Troubleshooting — 次に何を確かめるか”遅い query の実体とパラメータを特定し、plan、推定と実測の差、待機イベントを調べる。 Buffer の read をそのまま物理 disk read と断定しない。OS cache や storage の観測まで接続して考える。
資料を閉じて説明する:この index の列順はなぜこうしたか。データの大半が一顧客の注文なら何を確認し直すか。 学習した内容を面接形式で確かめるときは、テストシナリオ一覧から選ぶ。
一次資料の確認日:2026-09-07。実験対象:PostgreSQL 18。