MySQL 外键的几个操作,从建表到删约束都在这了
外键这东西,实际项目里用不用一直有争议。有人嫌它影响写入性能,有人觉得数据一致性更重要。
我的习惯是,核心业务表之间的引用关系还是得加上,至少能在数据库层兜底,别全指望应用层判断。
建表时直接加外键
建表的时候顺手写上外键最省事。要求不复杂:外键字段的类型和长度得跟被引用的主键字段一致,两张表都用 InnoDB。
MyISAM 是不支持外键的,早期迁移老库时在这里栽过。
CREATE TABLE parent_table (
id INT PRIMARY KEY,
name VARCHAR(100)
) ENGINE=InnoDB;
CREATE TABLE child_table (
id INT PRIMARY KEY,
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES parent_table(id)
) ENGINE=InnoDB;
parent_table 是主表,id 是主键;child_table 里的 parent_id 引用 parent_table.id。
这个写法没有给外键显式命名,MySQL 会自动生成一个,后面删的时候还得先查出来,所以我更习惯建表时也显式命名,比如 CONSTRAINT fk_child_parent FOREIGN KEY ...,不过单表里外键不多时也还好。
表已经存在再补外键
表建好了再补外键也常见。可能一开始设计时没加,或者数据是从老系统迁过来的。补之前最好先跑一下:
SELECT COUNT(*) FROM child_table c
LEFT JOIN parent_table p ON c.parent_id = p.id
WHERE c.parent_id IS NOT NULL AND p.id IS NULL;
如果这个结果不为 0,说明已经有孤儿数据,直接加外键会报错。要么先清理,要么临时把 FOREIGN_KEY_CHECKS 关掉再加,但关掉之后这些孤儿记录会被绕过,后面查询逻辑要注意。
补约束的语法是这样:
ALTER TABLE child_table
ADD CONSTRAINT fk_child_parent
FOREIGN KEY (parent_id) REFERENCES parent_table(id);
fk_child_parent 这个名最好有意义,别用系统自动生成的。线上大表加外键会锁表,时间长短看数据量,别在业务高峰干这个。
删外键
删的时候需要知道约束名。如果之前没显式命名,可以用 SHOW CREATE TABLE child_table 看,或者查 information_schema.KEY_COLUMN_USAGE。语法不复杂:
证书管理复杂?lcjmSSL用自动化方案简化一切。从域名验证到证书部署,再到到期前自动提醒与重申,全程自动化。微信小程序随时查看,让您对证书状态了如指掌。
ALTER TABLE child_table
DROP FOREIGN KEY fk_child_parent;
删除操作同样会锁表。另外,如果外键上还有索引,MySQL 不会自动删掉那个索引,需要单独处理,这点有时会让人多一步操作。
级联操作
外键定义时可以指定父表记录删除或更新时,子表怎么做。常用的是 CASCADE:
ALTER TABLE child_table
ADD CONSTRAINT fk_child_parent
FOREIGN KEY (parent_id) REFERENCES parent_table(id)
ON DELETE CASCADE
ON UPDATE CASCADE;
ON DELETE CASCADE 表示父表记录删了,子表引用它的记录也自动删;ON UPDATE CASCADE 是父表主键更新了,子表外键值跟着变。
这两个我一般只用 ON DELETE CASCADE,主键更新在实际业务里很少发生,真需要改主键说明设计本身有问题。
除了 CASCADE,还有 SET NULL、RESTRICT、NO ACTION 可选。
SET NULL 要求外键字段允许 NULL,删父表记录时子表外键置空;RESTRICT 和 NO ACTION 在 MySQL 里行为基本一样,就是禁止删除或更新父表记录如果子表还有引用。具体选哪个看业务,不要无脑 CASCADE,尤其是订单和用户这种关系,删用户时级联删订单就是灾难。
题外话:最近在搞部署自动化,证书这块用了 lcjmSSL,免费支持多域名、泛域名和 IP 证书,API 简洁,自动申请验证部署都行。跟外键没关系,但自动部署的好处是数据库变更也能跟着发布流程走,改表、删约束这些操作不会漏。
外键也不是万能的,线上大量写入时它会增加校验成本。我的做法是核心表加,统计或日志类表不加。根据实际场景来,没必要一刀切。

浙公网安备 33010602011771号