導入
第0章で「10万行でも SQL なら一瞬」と言いました。でも実は、何も考えないと DB は「先頭から1行ずつ全部見る」しかありません(フルスキャン)。10万行なら10万回の確認です。これを劇的に速くするのが インデックス(索引) です。本の巻末索引と同じ発想で、「この値はここ」という早見表を別に持ちます。
説明
インデックスの効き方は、辞書を引くのに似ています。
flowchart TB
subgraph NO["索引なし(フルスキャン)"]
A["1行目を見る → 違う<br/>2行目を見る → 違う<br/>… 10万行目まで全部確認"]
end
subgraph YES["索引あり"]
B["並べ替え済みの早見表で<br/>目的の値へ一気にジャンプ"]
end
NO -->|"CREATE INDEX で"| YES
インデックスは CREATE INDEX で作ります。「どの表の・どの列に索引を張るか」を指定します。
CREATE INDEX idx_users_city ON users(city);
これで WHERE city = '東京' のような検索が速くなります。SQLite には、クエリが索引を使うかどうかを見せてくれる EXPLAIN QUERY PLAN があります。索引を作る前後で見比べてみましょう。
-- 索引を作る前は SCAN(全部見る)と出る
EXPLAIN QUERY PLAN SELECT * FROM users WHERE city = '東京';
-- 索引を作る
CREATE INDEX idx_users_city ON users(city);
-- 作った後は SEARCH ... USING INDEX(索引で探す)に変わる
EXPLAIN QUERY PLAN SELECT * FROM users WHERE city = '東京';
万能ではありません。インデックスにはコストがあります。
- 書き込みが少し遅くなる…
INSERT/UPDATEのたびに索引も更新するため。 - 場所を取る… 早見表のぶんデータが増える。
だから「検索や結合・並べ替えでよく使う列」に絞って張るのが定石です。主キーには自動で索引が付きます。外部キー列(orders.user_id など、JOIN の ON で使う列)は、索引の有力な候補です。
やってみよう
初期表示の EXPLAIN QUERY PLAN ... をまず実行し、SCAN users のような表示(全部見る)を確認しましょう。次に CREATE INDEX idx_users_city ON users(city); を実行し、もう一度同じ EXPLAIN QUERY PLAN を走らせて、表示が SEARCH users USING INDEX ... に変わることを見比べてください。索引が「探し方」を変えた証拠です。
演習
products の category_id 列にインデックスを作ってください。名前は idx_products_category とします。
ヒント1を見る
CREATE INDEX 索引名 ON テーブル(列); の形です。
ヒント2を見る
CREATE INDEX idx_products_category ON products(category_id);