こんにちは、さるまりんです🐒
「このクエリ、遅い気がするけど、なんで?」
そんなときに役立つのが、PostgreSQLのEXPLAIN
コマンド!クエリがどう実行されるか、内部の計画を教えてくれる便利なツール。
実はこれまで使ったことがありませんでした。
今回はEXPLAIN
やEXPLAIN ANALYZE
を使って、クエリの動作を見て、改善していくことにチャレンジしてみたいと思います。
環境構築:DockerでPostgreSQLをすぐ試そう!
PostgreSQLを試せる環境をDockerでパパッと立ち上げます。
docker-compose.yml
はこれです。
version: '3'
services:
db:
image: postgres:16
container_name: postgres-explain
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: testdb
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
起動します
docker-compose up -d
接続します
docker exec -it postgres-explain psql -U postgres -d testdb
まずはサンプルテーブルで確認
PostgreSQLにusers
というサンプルテーブルを作って、適当にテストデータを1万件入れてみます。
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
age INT
);
-- 適当にデータを入れる(例:1万件)
INSERT INTO users (name, age)
SELECT 'user_' || i, (random() * 100)::int
FROM generate_series(1, 10000) AS s(i);
EXPLAIN
で実行計画を見る
次に、シンプルなクエリにEXPLAIN
をつけてみます。
EXPLAIN SELECT * FROM users WHERE age > 30;
実行結果:
QUERY PLAN
-------------------------------------------------------
Seq Scan on users (cost=0.00..189.00 rows=6972 width=17)
Filter: (age > 30)
Seq Scan
となっていますね。これは「全件走査」の意味。
つまり、インデックスを使わずにすべての行をチェックしたということです。
cost
は実行コストの推定値で、数値そのものよりも他のクエリとの相対的な比較に使います。
rows
は、条件にマッチすると予測されている行数です。
インデックスが無いので、シーケンシャルスキャンになってますね。
インデックスを作って再確認
CREATE INDEX idx_age ON users(age);
インデックスを作ったら、その効果を反映させるために ANALYZE
を実行します:
ANALYZE users;
そして再度EXPLAIN
を実行:
EXPLAIN SELECT * FROM users WHERE age = 99;
結果:
Bitmap Heap Scan on users (cost=5.15..72.27 rows=112 width=17)
Recheck Cond: (age = 99)
-> Bitmap Index Scan on idx_age (cost=0.00..5.12 rows=112 width=0)
Index Cond: (age = 99)
Index Scan
の文字がありますね。
無事、インデックスが使われています!
EXPLAIN ANALYZE
で実行時間もチェック!
実行計画に加えて、実際の実行時間も知りたいときはEXPLAIN ANALYZE
を使います。
EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;
結果:
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Seq Scan on users (cost=0.00..189.00 rows=6972 width=17) (actual time=0.009..0.743 rows=6996 loops=1)
Filter: (age > 30)
Rows Removed by Filter: 3004
Planning Time: 0.052 ms
Execution Time: 0.913 ms
actual time
は実際にかかった時間、rows
は実際に返された行数です。
Rows Removed by Filter
は条件に合わずスキップされた行、
Planning Time
/ Execution Time
は全体の所要時間を示しています。
実行プランに「実際の数字」が付くことで、推定と実際のズレもわかってきますね。
まとめ
遅いクエリがあったら、まずは EXPLAIN
!
実行計画を見て、インデックスが効いているか確認。
インデックスを作ったら ANALYZE
で統計情報を反映してから、もう一度 EXPLAIN
!
時間も知りたいときは EXPLAIN ANALYZE
です。
これまで使っていませんでしたが、「おや?」と思ったときは積極的に使ってみたいと思います。
便利に、上手に使って、快適に。
読んでくださってありがとうございました。
それではまた!