状況
キャンセル済み注文の明細を削除する本番作業。orders の主キーは id で、order_id という列はない。order_items には order_id 列がある。作業者の SQL は次のとおり。
この SQL で最も危ない点は?
DELETE FROM order_itemsWHERE order_id IN ( SELECT order_id FROM orders WHERE status = 'canceled');正答
- サブクエリの中では WHERE を使えないため、構文エラーで止まる
- orders に order_id がなく外側の列と解釈され、全明細が消えうる
- IN ではなく EXISTS を使わないと、削除が非常に遅くなる
- 外部キーがあると DELETE は必ず失敗するため、影響は出ない
解説
サブクエリの中で orders に存在しない order_id を書くと、多くの DB はエラーにせず、外側の order_items.order_id を参照したと解釈する。その結果、キャンセル済み注文が 1 件でもあれば条件はほぼ全行で真になり、明細がまとめて消える。正しくは SELECT id とする。実行前に同じ条件の SELECT で件数を確かめれば気づける。EXISTS との速度差は二次的な論点で、サブクエリでの WHERE は正しい構文である。
この問題を含む 実務シチュエーション のテストを制限時間つきで解く
実務シチュエーションクイズへ