【DB2026 #5】SQLのアンチパターン

アンチパターンをいくつか紹介。

N+1クエリ問題


  • 関連データを取得するために、ループの中で繰り返しクエリを発行してしまうこと
  • 具体例
    • 10件の注文を取得し、各注文に対して個別にSELECT * FROM order_items WHERE order_id = ?を実行→合計11回のクエリ
  • 問題点
    • クエリ数がデータ量に比例して増加し、レイテンシが急激に悪化する
    • DBへのコネクション負荷が増大する
  • 対策
    • JOINを使って1回のクエリで取得する
    • WHERE order_id IN (...) でまとめて取得する(バッチフェッチ)
    • ORMのeager loading機能を活用する(例:Railsのincludes、Laravelのwith、Djangoのprefetch_related)

列指定の省略(Implicit Columns)


  • SELECT * FROM table のように列を指定せずに全列を取得すること
  • 問題点
    • テーブルにカラムが追加・削除されたとき、アプリケーション側で想定しているカラム順序やデータ型が壊れる
    • 不要なカラムまで取得するため、ネットワーク帯域とメモリを無駄に消費する
    • インデックスのみで完結するクエリ(カバリングインデックス)が使えなくなり、パフォーマンスが低下する
  • 対策
    • 必要なカラムを明示的に列挙する:SELECT id, name, email FROM users
    • ORM(オブジェクト関係マッピング)を使う場合もeager loadingの範囲を意識する

暗黙の型変換(Implicit Type Conversion)


  • WHERE句などで型が一致しないカラムと値を比較し、暗黙の型変換が発生するパターン
  • 具体例
    • WHERE varchar_column = 12345(文字列カラムに数値リテラルを比較)
  • 問題点
    • インデックスが無視され、フルテーブルスキャンになる
    • 予期しない比較結果('0012' = 12 がtrueになる等)が生じる
  • 対策
    • 比較する値の型をカラムの型に合わせる:WHERE varchar_column = '12345'
    • SQLの厳密モード(strict mode)を有効にする

インデックスショットガン(Index Shotgun)


  • 「とりあえずインデックスを貼れば速くなる」と考え、闇雲にインデックスを追加するパターン
  • 問題点
    • INSERT / UPDATE / DELETE のたびにインデックスの更新コストが発生し、書き込み性能が低下する
    • ディスク容量を圧迫する
    • オプティマイザが最適なインデックスを選択しにくくなる
  • 対策
    • EXPLAIN ANALYZE で実際の実行計画を確認してからインデックスを追加する
    • 使用されていないインデックスを定期的に棚卸しする
    • 複合インデックスの列順を意識する(選択度の高い列を先頭にする)

SQLインジェクション(SQL Injection)


  • ユーザー入力を直接SQL文に連結してしまうパターン
  • 具体例
    • "SELECT * FROM users WHERE name = '" + userInput + "'" のような文字列結合
  • 問題点
    • 悪意あるユーザーが任意のSQLを実行でき、データの漏洩・改ざん・削除が可能
    • OWASP Top 10に常にランクインする深刻な脆弱性
  • 対策
    • プリペアドステートメント(バインドパラメータ)を必ず使用する
    • ORM / クエリビルダを活用する
    • 入力のバリデーション・エスケープを多層で行う(防御的プログラミング)