今回やること
この記事では、EXPLAIN を使って、SQLがテーブルをどう探そうとしているかを確認します。
インデックスは作るだけでなく、EXPLAINで使われているか確認することが大切です。
前提条件
- PostgreSQLなど
EXPLAINを使える環境がある SELECTとWHEREの基本を知っている- 結果表示はデータベースやバージョンによって少し異なる
Step 1: 練習用テーブルを作る
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL,
name TEXT NOT NULL
);
Step 2: データを入れる
少量データでは違いが見えにくいですが、手順を確認する目的で数件入れます。
INSERT INTO customers (id, email, name) VALUES
(1, 'sato@example.com', 'Sato'),
(2, 'suzuki@example.com', 'Suzuki'),
(3, 'tanaka@example.com', 'Tanaka');
大量データで試す場合は、学習用DBで別途データを増やしてください。
Step 3: EXPLAINを実行する
EXPLAIN
SELECT *
FROM customers
WHERE email = 'sato@example.com';
インデックスがない状態では、Seq Scan のような表示になることがあります。これは順番にテーブルを確認する全件スキャンです。
Step 4: インデックスを作る
CREATE INDEX idx_customers_email
ON customers (email);
email を検索条件に使うため、email にインデックスを作ります。
Step 5: もう一度EXPLAINする
EXPLAIN
SELECT *
FROM customers
WHERE email = 'sato@example.com';
行数が少ないテーブルでは、インデックスを作っても Seq Scan のままになることがあります。これは異常とは限りません。データベースが「この件数なら全件見た方が早い」と判断する場合があるからです。
インデックスを作ったのに使われないことはあります。EXPLAINで実際の計画を見ます。
Step 6: EXPLAIN ANALYZEの注意
PostgreSQLでは EXPLAIN ANALYZE を使うと、実際にSQLを実行して時間も測ります。
EXPLAIN ANALYZE
SELECT *
FROM customers
WHERE email = 'sato@example.com';
SELECT なら比較的安全ですが、UPDATE や DELETE に対して使うと実際に変更が走ります。変更系SQLで使う場合はトランザクションや検証環境で慎重に扱います。
Step 7: JOINで使う列を考える
注文テーブルの user_id のように、JOINでよく使う列もインデックス候補です。
CREATE INDEX idx_orders_user_id
ON orders (user_id);
JOINが遅いときは、JOIN条件に使う列がインデックス候補になることがあります。
よくあるエラー
| エラー | よくある原因 | 確認すること |
|---|---|---|
| インデックスが使われない | 行数が少ない | 異常とは限らない |
EXPLAIN ANALYZE で変更された | 更新系SQLに使った | 検証環境とトランザクションを使う |
| インデックス名が重複 | 同じ名前で作成済み | \di などで一覧確認 |
| 期待より速くない | 条件に合っていない | WHERE/JOIN/ORDER BYの列を確認 |
まとめ
EXPLAIN は、SQLがどのように実行されそうかを見るための道具です。Seq Scan は全件スキャン、Index Scan はインデックス利用の目安になります。インデックスを作ったら、実際に使われているか EXPLAIN で確認します。