萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 外鍵建立失敗 ERROR 150 (HY000) 九大原因排查與解決方案

MySQL 建立外鍵時報 ERROR 150 (HY000): Can't create table ... (errno: 150) 是經典難題,錯誤訊息不提示具體原因。本文整理**九大常見原因**、排查順序、驗證 SQL 與解決方案,助你快速定位修復。

一、九大核心原因與排查 SQL

#原因排查/驗證 SQL解決方案
1欄位類型/長度/符號不匹配
如 INT(10) vs INT(11)、INT vs BIGINT、SIGNED vs UNSIGNED
SHOW CREATE TABLE parent_table;
SHOW CREATE TABLE child_table;
對比欄位定義**完全一致**
修正子表欄位定義與父表主鍵**完全一致** (類型、長度、UNSIGNED、CHARSET、COLLATION)
2父表欄位無索引/非主鍵
被引用欄位必須是 PRIMARY KEY 或有 INDEX
SHOW INDEX FROM parent_table WHERE Column_name = 'ref_col';父表欄位加 PRIMARY KEY 或 INDEX idx_ref_col (ref_col)
3外鍵名稱衝突
資料庫級唯一,同名外鍵已存在
SELECT CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY';指定唯一名稱:CONSTRAINT fk_child_parent_unique FOREIGN KEY ...
4表引擎不支援外鍵
MyISAM 不支援,必須 InnoDB
SHOW TABLE STATUS LIKE 'table_name'; → Engine 欄位轉換引擎:ALTER TABLE t ENGINE=InnoDB;
5ON DELETE SET NULL 但欄位 NOT NULLSHOW COLUMNS FROM child_table LIKE 'fk_col'; → Null: No修改欄位 ALTER TABLE child MODIFY fk_col INT NULL; 或改 ON DELETE CASCADE/RESTRICT
6字元集/排序規則不一致
父子表/欄位 CHARSET/COLLATE 不同
SHOW CREATE TABLE parent_table;
SHOW CREATE TABLE child_table;
統一表/欄位 CHARSET (建議 utf8mb4) 與 COLLATE (utf8mb4_unicode_ci)
7外鍵欄位有 DEFAULT 值
如 DEFAULT 0 干擾外鍵語義
SHOW COLUMNS FROM child_table LIKE 'fk_col'; → Default: 0移除 DEFAULT:ALTER TABLE child ALTER COLUMN fk_col DROP DEFAULT;
8引用複合索引非最左列
父表複合索引 (a,b),子表引用 b
SHOW INDEX FROM parent_table; 檢查 Seq_in_index父表為被引用欄位建單獨索引,或調整複合索引順序
9ALTER TABLE 語法錯誤
語法拼寫、關鍵字順序
對照官方文檔核對使用標準語法:ALTER TABLE child ADD CONSTRAINT fk_name FOREIGN KEY (col) REFERENCES parent(col) ON DELETE CASCADE;

二、標準建立外鍵語法模板

ALTER TABLE `child_table`
ADD CONSTRAINT `fk_child_parent_unique_name`
FOREIGN KEY (`parent_id`)
REFERENCES `parent_table` (`id`)
ON DELETE RESTRICT   -- 或 CASCADE / SET NULL / NO ACTION
ON UPDATE CASCADE;   -- 建議 CASCADE,主鍵變更自動同步

三、排查實戰流程圖

1. 檢查兩表引擎 → 必須都是 InnoDB
2. 檢查父表被引用欄位 → 必須有索引 (PK/UNIQUE/INDEX)
3. 對比父子欄位定義 → 類型、長度、UNSIGNED、CHARSET、COLLATE 完全一致
4. 檢查外鍵名稱 → 資料庫級唯一
5. 檢查 ON DELETE/UPDATE 子句與欄位 NOT NULL 衝突
6. 檢查是否引用複合索引非最左列
7. 使用標準 ALTER TABLE 語法
8. 仍失敗 → 查看錯誤日誌: SHOW ENGINE INNODB STATUS\G (LATEST FOREIGN KEY ERROR 區塊)

四、查看 InnoDB 內部外鍵錯誤詳情

SHOW ENGINE INNODB STATUS\G
-- 關鍵區塊:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
2024-01-15 10:30:00 0x... Transaction:
TRANSACTION 12345, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
FOREIGN KEY ERROR: ... (具體原因文字描述)

此輸出會直接提示具體原因(如「Data type mismatch」、「Parent table has no index」等)。

五、最佳實踐建議

  1. 統一規範: 所有表 InnoDB、utf8mb4、主鍵 BIGINT UNSIGNED AUTO_INCREMENT。
  2. 命名規範: fk_子表_父表_欄位,全庫唯一。
  3. 工具生成: 使用 MySQL Workbench、DataGrip、MyEclipse 反向工程生成 DDL,避免手寫錯誤。
  4. 謹慎使用外鍵: 高併發寫入場景外鍵鎖開銷大,考慮應用層維護參考完整性、或用觸發器/軟刪除替代。

六、總結

ERROR 150 九成以上源於 **欄位定義不一致**、**父表無索引**、**引擎非 InnoDB**、**字元集不匹配**。按本文九大原因順序排查,配合 SHOW ENGINE INNODB STATUS 看內部錯誤詳情,可在分鐘級定位解決。**規範先行、工具生成、謹慎使用外鍵**,是長久之計。

copyright © 萬盛學電腦網 all rights reserved