外键的职责
外键把引用完整性交给数据库:子表外键列的值必须能在父表被引用列里找到,否则写入被拒绝。ON DELETE / ON UPDATE 决定父行被改动时子行怎么办——拒绝、跟着删、置空或置默认值。MySQL(InnoDB)与 PostgreSQL 都支持,但它会带来校验与加锁开销,进入写入路径。
基本信息
| 适用平台 | MySQL InnoDB 与 PostgreSQL 均已支持 |
|---|---|
| 语法 | FOREIGN KEY (子表列) REFERENCES 父表 (父表列) |
| 级联选项 | RESTRICT / NO ACTION / CASCADE / SET NULL / SET DEFAULT |
| 前提条件 | 父表被引用列需唯一索引;两表列类型与字符集一致 |
| 延迟校验 | PostgreSQL 支持 DEFERRABLE 延迟到提交时校验 |
典型使用场景
- 保证订单一定关联到存在的用户,杜绝孤儿记录
- 父行删除时按业务决定连带删除明细或直接拒绝
- 审计与日志类子表,防止写入不存在的业务主体
- 数据迁移时延后到提交再校验,减少中间态报错(PostgreSQL)
- 测试环境用级联删除快速清理关联数据
MySQL 建外键
MySQL 建外键
-- 先确认外键列有索引:InnoDB 缺索引时会自动建,显式建更可控
ALTER TABLE orders ADD INDEX idx_user_id (user_id);
ALTER TABLE orders
ADD CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users (id)
ON DELETE CASCADE ON UPDATE RESTRICT;
SHOW CREATE TABLE orders; -- 确认外键与索引都已生效PostgreSQL 建外键
PostgreSQL 建外键
ALTER TABLE orders
ADD CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users (id)
ON DELETE CASCADE ON UPDATE RESTRICT
DEFERRABLE INITIALLY IMMEDIATE; -- 需要时用 SET CONSTRAINTS DEFERRED 延迟校验
-- 查看外键定义
SELECT conname, confupdtype, confdeltype
FROM pg_constraint WHERE conrelid = 'orders'::regclass;级联选项语义
| 选项 | 父行被删除时 | 父行主键被更新时 |
|---|---|---|
| RESTRICT / NO ACTION | 有子行就拒绝删除 | 有子行就拒绝更新 |
| CASCADE | 连带删除所有子行 | 子行外键列跟着改成新值 |
| SET NULL | 子行外键置空(列必须可空) | 同样置空 |
| SET DEFAULT | 子行外键置为默认值(需存在于父表) | 同样置为默认值 |
CASCADE 的破坏力:删掉一条父行会连带清空全部相关子行。生产上启用前要确认业务语义,并先统计子表数据量,避免一条 DELETE 引发连锁删除。
外键不能跨实例,分库分表后数据库层面无法再保证一致性,只能靠应用层校验与对账补偿。另外高并发写入时外键检查会持有共享锁,可能放大锁竞争,大表上线前先压测。