今回行ったこと↓
「複数テーブルのJOINが続くクエリは読がにくい。サブクエリを使って2つのテーブルの結合処理を1つのまとまりにして、それに別名(AS)を付けてることで後続のJOINを読みやすくした」
イメージ:
長いJOIN列を一気に書くと混乱する →
2テーブルの結合をサブクエリとしてまとめる →
その結果にASで名前を付ける →
その結果に1テーブルを結合し、ASで名前を付ける →
同じことを繰り返し、全てのテーブル結合を行ったあとSELECTでデータ取得
WITH step1 AS (
SELECT u.id AS user_id, u.name
FROM users u
WHERE u.is_active = true
),
step2 AS (
SELECT s1.user_id, s1.name, o.id AS order_id, o.order_date
FROM step1 s1
LEFT JOIN orders o
ON s1.user_id = o.user_id
),
step3 AS (
SELECT s2., p.amount
FROM step2 s2
LEFT JOIN payments p
ON s2.order_id = p.order_id
),
step4 AS (
SELECT s3., s.status
FROM step3 s3
LEFT JOIN shipments s
ON s3.order_id = s.order_id
AND s.delivered = false
)
SELECT *
FROM step4;
↑結果JOINの書き方がスッキリする
という流れ。
「長くて読みづらいクエリ」例
SELECT
u.id,
u.name,
o.order_date,
p.amount,
s.status
FROM users u
LEFT JOIN orders o
ON u.id = o.user_id
LEFT JOIN payments p
ON o.id = p.order_id
LEFT JOIN shipments s
ON o.id = s.order_id
WHERE u.is_active = true
AND s.delivered = false;
メリットまとめ(可読性・保守性が向上)
①クエリの可読性が高くなる
結合をブロックごとに分けるので、何をしている部分なのかが明確になる。
② 処理の流れを段階別に検証しやすい
サブクエリ単体でSELECTして動作確認できる。
③JOIN条件のミスを防ぎやすい
巨大なSQLでJOINが続くほど、以下のようなミスが起きやすい。
ON 条件の書き忘れ
誤ったカラム参照
必要のないテーブルが残る
④ 役割ごとにまとめることで、後から見ても理解しやすい
「ユーザー情報をまとめる部分」「決済情報をまとめる部分」など、
SQL全体をパーツ化できるため、引き継ぎや改修が楽。チーム開発での情報共有が行いやすい。
⑤一度まとめたサブクエリを他でも再利用できる
処理速度(パフォーマンス)への影響
中身の最適化はPostgreSQLがやってくれため、多くの場合スピードはほぼ変わらない。
実際のパフォーマンスは EXPLAIN ANALYZE で確認する。