Mímisbrunnr知恵の泉

← データエンジニアリング 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:SQLの基礎(結合・集約・サブクエリ) | 関連:列指向ストレージと分析クエリシャッフルとパーティショニング

要点(BLUF)

概念 ── 本の索引と同じ

本で特定の語を探すとき、全ページめくる(全表走査)か、巻末の索引から該当ページへ飛ぶ(索引探索)か。インデックスは後者です。テーブルとは別に「列の値を整列した木」を持ち、値から行の位置へ最短で案内します。

flowchart TB
    Q["WHERE cust_id = 1"] --> D{"索引あり?"}
    D -->|なし| FS["全表走査:全行チェック O(N)"]
    D -->|あり| IS["B木をたどる:O(log N)で該当行へ"]

仕組み ── 実行計画で見る差

同じクエリを、インデックスの有無で比べます。

-- index なし
EXPLAIN QUERY PLAN SELECT * FROM orders WHERE cust_id = 1;
-- index を作る
CREATE INDEX idx_orders_cust ON orders(cust_id);
-- index あり
EXPLAIN QUERY PLAN SELECT * FROM orders WHERE cust_id = 1;

実行結果(実機・SQLite):

[index なし] SCAN orders
[index あり] SEARCH orders USING INDEX idx_orders_cust (cust_id=?)

SCAN orders=全行を読む。SEARCH ... USING INDEX=索引で該当行だけを探す。データが100万行なら、この差は劇的です(全走査100万 vs 木をlog桁たどる)。「なぜ遅いか」は推測せず、まずEXPLAINを見るのが鉄則です。

設計の勘所 ── どこに貼るか

効く場面効かない/逆効果
WHERE/JOIN/ORDER BYで頻出する列選択性が低い列(値の種類が少ない)
主キー・外部キー更新が極端に多いテーブル
値の種類が多い列(高選択性)全行の大半がヒットするクエリ

なぜそうするか ── 読みと書きのトレードオフ

なぜ全列に索引を貼らないのか。索引は読みを速くする代わりに書きを遅くするからです。INSERT/UPDATE/DELETEのたびに、対応する全インデックスの木を更新します。索引が10個あれば書き込みコストも増える。だから「読まれ方(クエリパターン)」を見て、効く列だけに最小限貼る。OLTP(書き込み多)とOLAP(読み多)で最適点が違うのも、このトレードオフの表れです。分析系では索引より列指向(→ 列指向ストレージと分析クエリ)が効くことも多い。

⚠️ よくある落とし穴

対応ラボ

data-engineering-study/labs/03_sql_optimization.pyPYTHONIOENCODING=utf-8 で実行・SCANSEARCH USING INDEXの変化を確認済み)。

関連

第3章 SQLとクエリ最適化 目次