JOINしすぎてない?SQLが遅くなる本当の理由と設計の考え方

こんにちは、さるまりんです 🐒🔧

SQLを書いていると、

  • とりあえずJOINでつなぐ
  • 必要なテーブルをどんどん追加する
  • 気づいたらたくさんのテーブルをつないでいる

こんな状態になること、ありませんか?

そして、

「あれ?なんかこのSQL遅いな…」

と感じることもあります。

今回はそうなる前に一度立ち止まって考えたい、

JOINと設計の関係

について見ていきたいと思います。

とりあえずJOIN、になっていない?

例えばこんなSQLです。

SELECT
  u.id,
  u.name,
  o.id AS order_id,
  p.name AS product_name
FROM users u
JOIN orders o ON u.id = o.user_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE u.id = 1;

正しいSQLですし、動きます。

でもこれ、

本当にこの構造で取得する必要がありますか?

と一度疑問を持つことが大切だと思っています。

JOINが増えると何が起きる?

JOINが増えると、内部ではこういうことが起きています。

  • テーブル同士の組み合わせを作る
  • 条件に合うものを探す
  • 不要な行を削る

つまり、

データ量が掛け算で増える可能性がある

ということです。

例えば、

  • users:1件
  • orders:100件
  • order_items:1000件

みたいな構造だと、

内部的にはかなりの組み合わせを処理することになります。

これが「遅くない?」の正体です。

※実際にはDBのオプティマイザが順序を調整しますが、JOINが増えるほどコストが増える傾向があるのは変わりません。

よくあるアンチパターン

■ ① 必要以上にJOINしている

「とりあえず全部つなぐ」

これはかなり多いです。

実際には、

  • 表示に必要なテーブルの必要なカラムだけ
  • 今の処理で必要な範囲だけ

に絞れることが多いです。

■ ② フィルタが後ろにある

WHERE u.id = 1

これがSQLの後ろの方にあると、

絞り込み前に大量のJOINが走る可能性があります

(DBによっては最適化されますが、期待しすぎは危険です)

a.id = b.a_id と JOIN の違い

ここ、なんとなく書いてしまっていることが多いポイントです。

例えばこの2つ。

-- パターン①
SELECT *
FROM a, b
WHERE a.id = b.a_id;
-- パターン②
SELECT *
FROM a
JOIN b ON a.id = b.a_id;

これらは、

意味としてはほぼ同じ(内部的にも同様に扱われることが多い)

です。

じゃあ何が違うのか?

違いは主に3つあります。

■ ① 可読性

FROM a, b
WHERE a.id = b.a_id;

条件なのか結合なのかが分かりにくい

JOIN b ON a.id = b.a_id;

「結合条件」として明確に表現できる

■ ② 書き間違いリスク

カンマ区切りの場合、

FROM a, b, c

と書いて、

WHERE a.id = b.a_id;

だけだと…

cが全件結合(クロス結合)になる

という事故が起きます。

■ ③ OUTER JOINが書けない

LEFT JOIN
RIGHT JOIN

は、JOIN構文でしか書けません。

実務ではJOIN構文を使うのが基本です

大事なのは「SQL」ではなく「設計」

ここが今回一番伝えたいところです。

JOINが増えているとき、

SQLをいじる前に、設計を疑う

という視点が大事です。

■ このテーブル構造、本当に適切?

  • 正規化しすぎていないか?
  • 逆に分かれすぎていないか?
  • よく使う組み合わせなのに毎回JOINしていないか?

■ 中間テーブルや集約はできないか?

例えば、

  • 注文+商品を毎回JOINする → 集約テーブルを持つ
  • よく使うデータ → キャッシュやマテリアライズドビューを使う

■ 必要なデータは何か?

全部取ってから削るのではなく、

最初から必要なものだけ取る設計

にする。

AIが書いたSQLに注意する

最近は ChatGPT などにSQLを書かせることも増えています。

ただし、

AIは「正しいSQL」は書けるけど
「最適な設計」は保証してくれない

という点には注意が必要です。

よくあるのが、

  • とにかくJOINを増やす
  • とりあえず全部つなぐ

“動くけど遅いSQL”

になってしまうケースです。

もちろんAIを正しく制御すれば書いてくれることもあるでしょうけどね。

だからこそ、

人間側が設計を理解していることが重要

になります。

まとめ

  • JOINは便利だが、増やしすぎるとパフォーマンスに影響する
  • a.id = b.a_id と JOIN は意味は近いが、JOIN構文を使うのが基本
  • 遅い原因はSQLではなく「設計」にあることが多い
  • 必要なデータだけを取る意識が大切

SQLが遅いとき、

つい「書き方」を疑ってしまいがちですが、

本当に見るべきなのは「構造」です。

この視点を持っておくと、

SQLの見え方がかなり変わってきます。

普段から「どうやって動いているのか」「だからどう作るのか」を考えることが大切ですね。

読んでくださってありがとうございます。
それではまた!