第07回: JOINの基本(INNER/LEFT) — ループで1件ずつ取るのをやめる

章: 第2章: 実務クエリ基礎

「投稿一覧を表示するたびにSQLが100本走る」——心当たりはありませんか?

投稿一覧を取得した後、各投稿の著者名を取るためにループで SELECT * FROM users WHERE id = ? を繰り返す——これがN+1問題の典型例です。100件の投稿があれば101本のSQLが走り、データが増えるほどレスポンスが悪化します。

JOINを使えば、複数テーブルの情報を1本のSQLで取得でき、N+1を根本から防げます。

INNER JOIN と LEFT JOIN——使い分けの判断軸

JOIN の種類を間違えると、取得したかったデータが消えたり、NULLが混入したりします。選択基準はシンプルです。「相手側のデータが必ず存在する」ならINNER JOIN、「相手側がなくても親を残したい」ならLEFT JOIN です。

INNER JOIN vs LEFT JOIN の比較

観点 INNER JOIN LEFT JOIN
結果に含まれる行 両テーブルに一致する行のみ 左テーブルの全行(右がなければNULL)
典型的な用途 投稿とその著者(著者は必ず存在) ユーザーと投稿(投稿がないユーザーも表示)
NULL混入 なし 右テーブルのカラムがNULLになり得る
間違えたときの症状 右がないレコードが消える 想定外のNULLでアプリ側エラー

チェックポイント: LEFT JOINの結果は右テーブルのカラムがNULLになる行を含みます。アプリ側でNULLチェックを忘れると undefinednull pointer 系のエラーが発生します。取得直後に WHERE p.id IS NOT NULL で存在確認するか、アプリ側でガード処理を入れましょう。

実際のコードのサンプル


SELECT p.id, p.title, u.name AS author_name
FROM posts p
INNER JOIN users u ON p.user_id = u.id;

SELECT u.id, u.name, p.title
FROM users u
LEFT JOIN posts p ON p.user_id = u.id;

まとめ & 次のステップ

  • INNER JOINは両テーブルに一致する行のみを返す。片方にデータがない行は結果から除外される
  • LEFT JOINは左テーブルの全行を返す。右テーブルに一致がない場合はNULLで補完される
  • JOINのON句に使うカラムにはインデックスを張ることで、大量データでも高速に結合できる
  • N+1はJOINやIN句による一括取得で解消する。ループ内のSQLは即疑うべきシグナル

次回は 「GROUP BYと集計関数」 を学びます。売上合計・投稿数カウントなど、レポート系機能に欠かせない集計クエリの書き方を確認します。

Related Articles