首页/数据/SQL 速查/级联删除与外键动作
变更与事务52 条

级联删除与外键动作

外键的 ON DELETE 动作决定父行删除时子行的命运:CASCADE 连带删除、SET NULL 置空、RESTRICT/NO ACTION 阻止删除。

SQL 速查数据更新于 2026-10-13

级联删除是什么

外键约束上的 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 要求外键列上必须有索引,缺少索引时建约束会自动创建;如果索引缺失且被手动删除,级联删除会退化为全表扫描,删一行就锁住整张子表。

易错点

  • 线上误删主表一行,级联把大量明细一并删除,未包事务时无法回滚,只能靠备份恢复
  • 外键列缺索引或索引被删,级联删除走全表扫描并长时间持锁,阻塞整张子表的写入
  • 过度依赖 CASCADE 而放弃应用层校验,删除范围失控
  • 给本来允许 NULL 的列写 SET NULL 却没确认可空性,建约束直接报错或产生孤儿数据

数据来源与参考

  • MySQL 8.0 Reference Manual · FOREIGN KEY Constraints
  • PostgreSQL Documentation · Foreign Keys
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌