1 つの誤解された CASCADE コマンドが、数秒で本番データを消し飛ばすことがあります。このキーワードは無害に見えますが、データベーススキーマ全体にまたがる削除を引き起こせます。
Bytebase の SQL レビュー には、CASCADE 障害を防ぐためのルールが含まれます。
-
ON DELETE 句に CASCADE オプションを使うことを禁止する:
ON DELETEのCASCADEオプションは、依存オブジェクトの大量削除や変更を引き起こし、想定外の結果につながる。 -
テーブル削除時に CASCADE を使うことを禁止する: テーブル削除時の
CASCADEオプションは、依存オブジェクトの大量削除や変更を引き起こし、想定外の結果につながる。
CASCADE とは
SQL における CASCADE は 2 つの文脈で現れます。
外部キー制約での CASCADE
CREATE TABLE posts (
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE -- ユーザーを削除すると、その投稿もすべて削除される
);TRUNCATE 操作での CASCADE
TRUNCATE TABLE users CASCADE; -- users と、それを参照するテーブルすべてを truncate する補足: TRUNCATE ... CASCADE は PostgreSQL 固有です。外部キーで依存しているテーブルを自動的に truncate するこの挙動は、MySQL、SQL Server などの他データベースには存在しません。Oracle にも TRUNCATE ... CASCADE はありますが、目的は別 (マテリアライズドビュー) です。
これはとくに危険です — 多くの開発者がその挙動を誤解しています。
よくある誤解
あるチームがデータベースを移行していて、新テーブルからテストデータをクリーンアップしたい、という場面を想像してください。開発者は次を実行します。
TRUNCATE TABLE new_feature_table CASCADE;意図: 新テーブルからテストデータを削除する。
仮定: CASCADE は他テーブルの関連テストデータだけを消すはず。
実際に起きたこと: TRUNCATE ... CASCADE は new_feature_table へ外部キーを持つすべてのテーブルの全データを削除しました — 数年分の本番データを含めて。
ここでの決定的な誤解は: TRUNCATE TABLE A CASCADE は B テーブルの「関連行」を消すのではないということです。それは A を参照する外部キーを持つテーブルそのものを truncate します。相互参照が複雑なスキーマでは、1 つの CASCADE がデータベース全体を吹き飛ばし得ます。
データベースを守る方法
1. 明示的な DELETE 文を使う
-- ❌ 危険: CASCADE が想定外のテーブルに波及する
TRUNCATE TABLE users CASCADE;
-- ✅ 安全: 何を消すかを完全に制御できる
DELETE FROM user_sessions WHERE user_id IN (SELECT id FROM users WHERE ...);
DELETE FROM users WHERE ...;2. 自動 SQL レビューを導入する
Bytebase を使って、実行前にすべての SQL を自動スキャンし、本番での危険な CASCADE 操作をブロックする。
3. 危険な権限を取り上げる
REVOKE TRUNCATE ON ALL TABLES IN SCHEMA public FROM app_user;4. マイグレーションを徹底的にテストする
本番ライクなデータで、ステージングでフルマイグレーションを実行し、影響範囲を確認し、ロールバック手順をテストする。
5. より安全な外部キーオプションを使う
ON DELETE CASCADE の代わりに ON DELETE RESTRICT や ON DELETE SET NULL を検討する。
まとめ
CASCADE キーワードはデータベース全体にまたがる自動削除を引き起こせます。最も重要な点: TRUNCATE TABLE A CASCADE は A を参照する外部キーを持つすべてのテーブルを truncate します — 関連行だけではありません。
データベースを守る:
- 明示的な DELETE 文でデータ削除を完全に制御する
- Bytebase の SQL レビュールールで本番の CASCADE をブロックする
- アプリケーションユーザーから TRUNCATE 権限を取り上げる
- スキーマ変更は必ずステージングでテストする