
AIに書かせたSQLの確認ポイント|N+1・インデックス漏れ
「このデータの一覧、SQLで取りたいんだけど」とAIに頼むと、きれいなクエリがすぐ返ってきます。 コピーして実行。テスト環境ではパッと表示される。よし、次へ——。
その気持ち、よく分かります。SQLは書けなくはないけれど、毎回きっちり組むのは面倒だし、AIが出したものが動いているなら、それでいいじゃないか、と。でも、SQLは「動くかどうか」と「本番で速いかどうか」がまるで別の話なんですよね。テスト用の数十件では一瞬でも、本番の何万行・何十万行になった途端に、急に重くなる。しかもその原因は、画面を見ているだけでは気づけない所に潜んでいます。
この記事は、AIに書いてもらったSQL(と、それを呼ぶコード)を、本番に出す前に確かめる型の話です。全部を疑ってかかろう、という話ではありません。「動いた」の一歩先で、N+1・インデックス・取りすぎの3つだけ見る——それだけで、リリース後に「なんか遅い」と呼び出される事故がかなり減ります。責める話ではないので、気楽に読んでください。
結論:AIが書いたSQLは、3点だけ確認します。①N+1になっていないか(一覧を出すのに、1件ごとに追加のクエリを投げていないか。件数が増えるほど問い合わせ回数が跳ね上がる)、②絞り込みにインデックスが効くか(WHEREやJOINの条件列にインデックスがあるか。無いと全件走査になり、データが増えるほど遅くなる)、③取りすぎ・書き換えの危険はないか(SELECT *で不要な列まで引いていないか、UPDATE/DELETEにWHEREが付いているか)。確かめ方は、本番に近い件数を用意して、EXPLAINで実行計画を1回見るだけ。全件走査(Seq ScanやfullなどのScan)が出ていないか、想定どおりのインデックスが使われているかを見ます。迷ったらAIに「このクエリはN+1にならない?インデックスは何が要る?」と説明させてから判断する。SQLは、遅さが本番でしか出ないのがこわい所。出す前にひと目、実行計画を見るのが一番安い保険です。
一度に全部やろうとしなくて大丈夫です。 まずは「一覧を出すクエリだけ、本番くらいの件数で1回動かしてみる」。ここから始めましょう。
何が起きているのか——「動くSQL」と「速いSQL」は別物

まず、なぜ確認が要るのかを共有させてください。AIのSQLが下手、という話ではありません。むしろ、文法として正しく、読みやすいクエリを返してくれることが多いです。問題は、AIが「あなたのデータが本番でどれくらいの量になるか」「どんなインデックスが張ってあるか」を知らないまま書いていることにあります。
AIは、渡された要件に対して「一般的に正しいSQL」を組みます。でも、速さはデータ量とインデックスと使われ方で決まる。ここはAIの手元に情報がありません。その結果、こんなことが起きます。
- 一覧のたびに1件ずつ問い合わせる(N+1):たとえば注文一覧を出すコードで、注文を100件取ったあと、その1件ごとに「この注文の顧客名は?」と別のクエリを100回投げる。テストの3件なら気づきませんが、本番で1000件になると、問い合わせが1000回以上に膨らみます。
- 絞り込み条件にインデックスが無い:
WHERE status = '未発送'のような条件でも、その列にインデックスが無ければ、データベースは全件を上から順に調べます(全件走査)。数百件なら一瞬、数十万件なら目に見えて遅くなります。 - 必要以上に取ってくる:
SELECT *で全列を引く、LIMITを付けずに全件返す、大きなテーブルを不用意にJOINする。動きはしますが、データが増えるほどメモリも転送量も膨らみます。 - 危ないクエリをさらっと混ぜる:
UPDATEやDELETEにWHEREを付け忘れると、全行が書き換わる。AIが例として出したものをそのまま本番で流すと、取り返しがつきません。
どれも共通するのは、テスト環境の少ないデータでは一見うまくいってしまうこと。だから「動いたからOK」で通ってしまい、遅さや事故は本番で初めて顔を出します。 ここで一拍おいて、回数・インデックス・取得量を見る。次から、その具体的な見方を順にいきます。
① N+1になっていないか——「一覧のたびに何回問い合わせている?」
いちばん多くて、いちばん効くのがN+1のチェックです。名前は難しそうですが、中身は単純で、「一覧を出すのに、1件ごとに追加の問い合わせを投げていないか」という話です。1回で済むはずが「1+N回」になるので、N+1と呼ばれます。
見つけ方は、SQL単体ではなくそれを呼ぶコードの側を見ます。
- ループの中でクエリを呼んでいないか:一覧をループで回しながら、その中で「この行に紐づく別データ」を毎回取りに行っていたら、ほぼN+1です。AIは「まず一覧を取る」「各行の詳細を取る」を素直に分けて書きがちで、これが起きやすい。
- 発行されたクエリのログを1回見る:多くのフレームワークは、実行したSQLをログに出せます。一覧を1回表示して、同じ形のクエリが何十回も並んでいないかを見る。並んでいたら、それがN+1の正体です。
- 直し方はAIにも相談できる:「これN+1になってるから、まとめて取る形に直して」と頼むと、
JOINで1回にまとめたり、IN句で必要なIDをまとめて引く形(一括取得)を出してくれます。ただし直した版も、次のインデックスのチェックは必要です。
件数を増やして初めて見える:N+1は、テストの数件では体感できません。本番に近い件数を入れてから、表示にかかる時間と発行クエリ数を見るのが確実です。数件で「速いね」と判断しないのがコツです。
一覧・検索・詳細まとめ表示など、「複数件を扱う画面」ほどN+1が出やすいと覚えておくと、見る場所を絞れます。AIにコードを書かせる前提のそろえ方はAIにコードを書かせる前に渡す前提と制約、既存のコードに馴染ませる文脈の渡し方は既存コードベースにAIを馴染ませる文脈の渡し方も下敷きになります。
② インデックスが効くか——実行計画を1回だけ見る
N+1を潰しても、その1回のクエリ自体が遅ければ意味がありません。ここで見るのがインデックスです。インデックスは、本の索引のようなもの。無いと、データベースは目的の行を探すのにテーブルを丸ごと上から調べます(全件走査)。
確かめる決め手は、EXPLAINで実行計画を見ることです。クエリの前に EXPLAIN(データベースによっては EXPLAIN ANALYZE)を付けて実行すると、「このクエリを、データベースがどう処理するつもりか」が表示されます。難しく読み込まなくて大丈夫。最初は次の2点だけ見ます。
- 全件走査になっていないか:実行計画に「Seq Scan」「full」「ALL」など、テーブル全体を走査する表示が出ていたら要注意。
WHEREやJOINの条件列にインデックスが無い合図です。小さなテーブルならそれでも速いですが、育つテーブルなら手を打っておきます。 - 狙ったインデックスが使われているか:「Index Scan」など、インデックスを使っている表示が出ていれば、まず一安心。ただし、意図と違うインデックスを使っていることもあるので、絞り込みの主役になる列(よく検索する列、外部キーなど)にインデックスがあるかを合わせて確認します。
インデックスは万能ではありません。多すぎると書き込みが遅くなるし、あっても条件の書き方次第で効かないこともあります(列を関数で加工している、あいまい検索の先頭が%になっている、など)。ここは深追いせず、「よく絞り込む列に索引があるか」「実行計画で全件走査が出ていないか」の2点をまず押さえれば十分です。
AIに相談するなら、EXPLAINの結果を貼って「この実行計画、全件走査になってない?どの列にインデックスを張ると効く?」と聞くのが早いです。読み解きを手伝ってくれます。ただしAIの提案も鵜呑みにはせず、実際に張って計測して確かめる——この順番は崩さないでください。
③ 取りすぎ・危険な書き換えはないか——最後の安全確認
実在の速さの話が済んだら、最後に「取りすぎていないか」「危ない操作が混じっていないか」を確認します。ここは動かしても気づきにくく、あとから効いてくる所です。
- **
SELECT *を使っていないか**:必要な列だけ書くのが基本です。全列を引くと、使わないデータまで運ぶことになり、テーブルの列が増えるほど重くなります。AIは横着して*を出しがちなので、必要な列名に絞るだけでも効きます。 - 件数の上限(
LIMIT)があるか:一覧や検索で、LIMITもページングも無いと、データが増えた将来に全件を一気に返してしまいます。表示に必要な分だけ取る形になっているか見ます。 UPDATE/DELETEにWHEREがあるか:これは速さではなく事故防止です。AIが出した例にWHEREが付いていない、あるいは条件が緩いと、意図せず広い範囲を書き換えます。本番で流す前に必ず条件を確かめ、可能なら先に同じ条件でSELECTして対象件数を確認します。- 入力を直接つないでいないか:ユーザー入力をSQL文にそのまま埋め込む書き方(文字列連結)は、SQLインジェクションの入り口です。プレースホルダ(パラメータ化)を使う形になっているか確認します。ここはセキュリティの話なので、AI生成コードのセキュリティ確認|見落としやすい穴も合わせてどうぞ。
判断に迷ったら、AI自身に説明させるのが手っ取り早いです。 「このクエリで取りすぎている列はない?WHEREの付け忘れや、入力をそのままつないでいる所はない?」と聞くと、危ない点が言葉になって出てきます。その説明を読んで納得できれば採用、あやしければ直す。受け取ったコード全体の見方はAI生成コードのレビュー・検証チェックリストに整理しています。
明日からやること(本番に出す前の3つ)
重い仕組みは要りません。まずこの3つだけ。
- 一覧・検索の画面で、発行クエリ数をログで1回見る:同じ形のクエリが何十回も並んでいたらN+1。まとめて取る形に直す。ここが一番効きます。
- 遅くなりそうなクエリに
EXPLAINを1回かける:全件走査(Seq Scan / full / ALL)が出ていないか、狙った列にインデックスがあるかを見る。 - **
SELECT *・LIMITなし・WHEREなしの3つを目視で確認する**:取りすぎと危険な書き換えを、本番で流す前に1回だけチェックする。
この3つは、慣れれば合わせて数分です。本番で「なんか遅い」「データが消えた」と対応することを思えば、ずっと軽い。 全部を毎回きっちりやらなくても、「一覧はクエリ数を見る」から始めれば十分です。
AIに書かせたSQLの確認チェックリスト
本番に出す前に、さっと確認します。全部に○が要るわけではなく、そのクエリで気になる所だけで十分です。
① N+1(問い合わせ回数)
- 一覧・検索の表示で、発行クエリ数を実際に見たか
- ループの中で1件ずつ別クエリを投げていないか
- 本番に近い件数で、表示にかかる時間を確かめたか
② インデックス(絞り込みの速さ)
-
EXPLAIN(実行計画)を1回見たか - 全件走査(Seq Scan / full / ALL)が出ていないか
- よく絞り込む列・
JOINの条件列にインデックスがあるか
③ 取りすぎ・安全
-
SELECT *になっていないか(必要な列に絞れているか) - 件数の上限(
LIMIT・ページング)があるか -
UPDATE/DELETEにWHEREが付き、対象件数を確認したか - 入力をプレースホルダで渡しているか(文字列連結でないか)
- (迷ったら)AIに「N+1・取りすぎ・危険な操作はない?」を説明させたか
この記事のまとめ
AIが書くSQLは、たいてい文法として正しく、そのまま動きます。 それでも、本番に出す前のひと呼吸——N+1になっていないか、インデックスが効くか、取りすぎや危険な書き換えはないか——を挟むだけで、リリース後に効いてくる事故がずいぶん減ります。全部を疑う必要はありません。「一覧はクエリ数を見る」「怪しいクエリはEXPLAINを1回」。まずはこの一手からで十分です。

SQLの速さは、本番でしか本当のことが分からない——だからこそ、出す前のひと目が効きます。 今日、「一覧のクエリ数を1回だけ見られた」なら、それはもう将来の自分を助ける一手です。受け取ったコード全体の見方はAI生成コードのレビュー・検証チェックリスト、そのまま使わないための動作確認は生成コードをそのまま使わない最低限の動作確認の型も、必要なときにのぞいてみてください。