MySQL 5.0+ 源碼安裝預設啟用 MyISAM,不支援外鍵約束。本文詳解如何檢查引擎支援、啟用 InnoDB、建表指定引擎、全域預設引擎切換,並對比 InnoDB/MyISAM 關鍵差異。
mysql> SHOW VARIABLES LIKE 'have_%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| have_innodb | DISABLED | -- 關鍵:DISABLED 表示未啟用
| have_archive | YES |
| have_blackhole_engine | YES |
| have_csv | NO |
| have_federated_engine | DISABLED |
| have_geometry | YES |
| have_merge_engine | YES |
| have_query_cache | YES |
| have_rtree_keys | YES |
| have_symlink | YES |
+--------------------------+--------+
have_innodb = DISABLED 表示 InnoDB 引擎未載入,無法使用外鍵、事務、行鎖等功能。
my.ini、Linux /etc/my.cnf 或 /etc/mysql/my.cnf[mysqld] 區塊找到 skip-innodb# skip-innodbSHOW VARIABLES LIKE 'have_innodb'; 應顯示 YES
-- 新建表指定引擎
CREATE TABLE `orders` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT UNSIGNED NOT NULL,
`amount` DECIMAL(10,2) NOT NULL,
PRIMARY KEY (`id`),
INDEX `idx_user_id` (`user_id`),
CONSTRAINT `fk_orders_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 現有表轉換引擎
ALTER TABLE `orders` ENGINE=InnoDB;
在 my.cnf [mysqld] 加入:
default-storage-engine = InnoDB
# 或舊版參數名
default_table_type = InnoDB
重啟後,未指定 ENGINE 的新表自動使用 InnoDB。驗證:SHOW ENGINES; 查看 DEFAULT 欄位。
注意:MySQL 5.0.22 某版本此參數可能無效,建議顯式指定 ENGINE=InnoDB。
| 特性 | MyISAM | InnoDB | 外鍵相關影響 |
|---|---|---|---|
| 外鍵約束 | 不支援 | 支援 | 核心差異 |
| 事務 (ACID) | 不支援 | 支援 | 外鍵需事務保證一致性 |
| 鎖粒度 | 表鎖 | 行鎖 | 高併發下外鍵檢查不阻塞無關行 |
| 聚簇索引 | 無 | 主鍵聚簇 | 外鍵引用主鍵效能極高 |
| 崩潰恢復 | 需手工修復 | 自動 Redo/Undo 恢復 | 外鍵完整性在崩潰後自動保證 |
| COUNT(*) | 極快(元資料) | 全表掃描 | 統計查詢需注意 |
| AUTO_INCREMENT | 允許聯合索引非首欄 | 必須為索引首欄 | 建表需調整索引順序 |
| 全文索引 | 支援(早期) | 5.6+ 支援 | 早期版本需權衡 |
| DELETE FROM table | 重建表(快) | 逐行刪除(慢) | 大量清理需權衡 |
| LOAD TABLE FROM MASTER | 支援 | 不支援 | 主從同步初始化需轉 MyISAM 導入再轉回 |
即使使用 InnoDB,若 SQL 無法使用索引精確定位行,仍會鎖全表:
-- 範例:LIKE 以萬用字元開頭,無法用索引 → 全表掃描 → 鎖全表
UPDATE `table` SET `num` = 1 WHERE `name` LIKE '%aaa%';
解決:優化查詢走索引、或接受短暫表鎖。
-- 插入違反外鍵的資料應報錯
INSERT INTO `orders` (`user_id`, `amount`) VALUES (99999, 100);
-- ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
-- 查看外鍵定義
SHOW CREATE TABLE `orders`;
-- 刪除被引用的父記錄應報錯(或 CASCADE)
DELETE FROM `users` WHERE `id` = 1;
-- ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails