级联删除是什么
外键约束上的 ON DELETE 动作决定父表行被删除时子表怎么办:CASCADE 删掉子行,SET NULL 把子行外键置空,RESTRICT / NO ACTION 直接报错阻止删除。MySQL 的 InnoDB、PostgreSQL、SQL Server、Oracle 都支持这几种动作,差别主要在细节:MySQL 里 RESTRICT 与 NO ACTION 等价且立即检查,PostgreSQL 的 NO ACTION 可以声明延迟到事务提交时才检查。级联删除会沿外键链继续传播,删一行可能连带清掉多层子表数据,是生产事故的常见来源。
基本信息
| 适用平台 | MySQL InnoDB / PostgreSQL / SQL Server / Oracle |
|---|---|
| 常用动作 | ON DELETE CASCADE、ON DELETE SET NULL、ON DELETE RESTRICT / NO ACTION |
| SET NULL 前提 | 外键列必须允许 NULL,否则建约束时报错 |
| MySQL 限制 | 语法接受 SET DEFAULT,但 InnoDB 引擎会拒绝,实际不可用 |
| 检查时机 | MySQL 立即检查;PostgreSQL 的 NO ACTION 可 DEFERRABLE 延迟到提交 |
典型使用场景
- 强从属关系:订单删除时明细一并清理,避免孤儿数据
- 配置从属:主配置删除后,子配置项随之失效并删除
- 任务与作业记录:任务删除时历史执行记录一起清理
- 弱关联:项目删除后任务保留但把 project_id 置空(SET NULL)
- 保守策略:核心主表用 RESTRICT,逼迫应用显式处理子数据
定义关联动作
定义关联动作
ALTER TABLE order_items
ADD CONSTRAINT fk_items_order
FOREIGN KEY (order_id) REFERENCES orders (id)
ON DELETE CASCADE # 父单删除时明细自动删除
ON UPDATE RESTRICT; # 父表主键被改动时直接拒绝
ALTER TABLE tasks
ADD CONSTRAINT fk_tasks_project
FOREIGN KEY (project_id) REFERENCES projects (id)
ON DELETE SET NULL; # 外键列必须允许 NULL查看现有关联动作
查看现有关联动作
# MySQL:从数据字典读出每张表的删除规则
SELECT table_name, constraint_name, delete_rule, update_rule
FROM information_schema.referential_constraints
WHERE constraint_schema = DATABASE();
-- PostgreSQL:查约束定义文本
SELECT conrelid::regclass AS child_table, conname, pg_get_constraintdef(oid)
FROM pg_constraint
WHERE contype = 'f' AND confrelid = 'orders'::regclass;关联动作对照
| 动作 | 行为 | 适用判断 |
|---|---|---|
| CASCADE | 子行随父行一起删除 | 强从属关系,子数据离开父数据没有意义 |
| SET NULL | 子行外键置为 NULL | 弱关联,子数据需要保留 |
| RESTRICT / NO ACTION | 存在子行时拒绝删除父行 | 核心主表默认策略,强制应用显式处理 |
| SET DEFAULT | 子行外键置为默认值 | InnoDB 拒绝,基本不用 |
执行 DELETE 前先确认下游有没有级联链:一条 DELETE 可能波及多张表,且 InnoDB 的级联删除不激活子表上的触发器,审计与回滚预案都会漏掉这部分数据。
InnoDB 要求外键列上必须有索引,缺少索引时建约束会自动创建;如果索引缺失且被手动删除,级联删除会退化为全表扫描,删一行就锁住整张子表。