外鍵是關係型資料庫維護參照完整性的核心機制。MySQL 早期為效能不支援外鍵,InnoDB 引擎引入後成為標準配置。本文系統講解外鍵建立條件、語法、級聯動作、效能權衡及避坑指南。
ENGINE=InnoDB (MyISAM/Memory 忽略外鍵定義)。PRIMARY KEY 或 UNIQUE KEY 或單獨 INDEX。子表外鍵欄位自動建立索引 (5.7+)。INT UNSIGNED ≠ INT SIGNED,VARCHAR(50) utf8mb4 ≠ VARCHAR(50) utf8。-- 父表:物種字典
CREATE TABLE `species` (
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `species` (`name`) VALUES ('Orangutan'), ('Elephant'), ('Hippopotamus'), ('Yak');
-- 子表:動物園動物
CREATE TABLE `zoo` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`species_id` TINYINT UNSIGNED NOT NULL,
INDEX `idx_species` (`species_id`), -- 子表外鍵欄位索引 (5.7+ 自動建立)
PRIMARY KEY (`id`),
CONSTRAINT `fk_zoo_species` FOREIGN KEY (`species_id`) REFERENCES `species` (`id`)
ON DELETE RESTRICT -- 刪除父記錄時:拒絕 (默認)
ON UPDATE CASCADE -- 更新父主鍵時:級聯更新子表
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
| 動作 | ON DELETE | ON UPDATE | 適用場景 |
|---|---|---|---|
| RESTRICT / NO ACTION | 拒絕刪除父行,報錯 1451 | 拒絕更新父主鍵 | 核心字典表、嚴禁孤兒記錄場景 (默認) |
| CASCADE | 級聯刪除子表關聯行 | 級聯更新子表外鍵值 | 明確從屬關係:訂單-明細、文章-評論 |
| SET NULL | 子表外鍵設為 NULL (需欄位允許 NULL) | 子表外鍵設為 NULL | 弱關聯:用戶-收貨地址 (用戶刪除保留地址) |
| SET DEFAULT | 子表外鍵設為預設值 (需定義 DEFAULT) | 同左 | 極少用,MySQL 解析器支援但存儲引擎忽略 |
ON UPDATE CASCADE 需鎖定所有子表關聯行,大批量更新極其危險 (鎖升級、死鎖風險)。強烈建議主鍵不可變,避免 ON UPDATE CASCADE。ON DELETE CASCADE 需掃描子表索引刪除關聯行,大量刪除導致長事務、Binlog 膨脹、主從延遲。S-lock (父表) + X-lock (子表),多事務交叉訪問易形成死鎖 (Error 1213)。JOIN、WHERE 加速。FOREIGN KEY 元數據可被工具 (DataGrip, Workbench) 產生 ER 圖、自動生成關聯查詢。ON DELETE RESTRICT 防誤刪。BIGINT UNSIGNED AUTO_INCREMENT 或 UUID,絕不更新主鍵,移除 ON UPDATE CASCADE。is_deleted=1 代替物理刪除,避免級聯刪除風暴。定期分區/歸檔歷史數據。SET FOREIGN_KEY_CHECKS=0; 導入 → SET FOREIGN_KEY_CHECKS=1; 驗證。切記重新啟用並驗證。SELECT c.* FROM child c LEFT JOIN parent p ON c.fk = p.id WHERE p.id IS NULL; 定期掃描。-- 查看所有外鍵
SELECT TABLE_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, DELETE_RULE, UPDATE_RULE
FROM information_schema.REFERENTIAL_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = 'your_db';
-- 刪除外鍵 (需先知 CONSTRAINT_NAME)
ALTER TABLE `zoo` DROP FOREIGN KEY `fk_zoo_species`;
-- 新增外鍵到現有表
ALTER TABLE `zoo` ADD CONSTRAINT `fk_zoo_species` FOREIGN KEY (`species_id`) REFERENCES `species` (`id`) ON DELETE RESTRICT;
結語:外鍵是數據完整性的最後防線,而非效能加速器。在單體架構、核心業務、中小數據量場景下大膽使用;在高併發寫入、大批量變更、分庫分表架構下謹慎評估或移至應用層。理解鎖機制、級聯風險、死鎖模式,才能駕馭外鍵這把雙刃劍。