業務增長常需將表從 MyISAM 轉為 InnoDB 以支援交易/行鎖,或反向轉換利用 MyISAM 全文索引。本文詳細說明三種轉換方法的適用場景、操作步驟、風險與優化技巧。
ALTER TABLE my_table ENGINE = InnoDB;
# 1. 匯出結構與資料
mysqldump -u root -p --single-transaction --routines --triggers db_name table_name > table_dump.sql
# 2. 編輯 SQL 檔:修改 ENGINE=InnoDB、調整索引、更名表名
sed -i 's/ENGINE=MyISAM/ENGINE=InnoDB/g' table_dump.sql
# 重要:更改表名避免衝突,如 CREATE TABLE `table_name_new` ...
# 3. 匯入新表
mysql -u root -p db_name < table_dump.sql
# 4. 驗證無誤後重命名
RENAME TABLE table_name TO table_name_old, table_name_new TO table_name;
DROP TABLE 預設包含在 dump 中需小心-- 1. 複製結構 (含索引、約束)
CREATE TABLE new_table LIKE old_table;
-- 2. 修改新表引擎
ALTER TABLE new_table ENGINE = InnoDB;
-- 3. 分批複製資料 (避免巨大交易、Undo Log 膨脹)
-- 假設 id 為主鍵遞增
SET @batch_size = 10000;
SET @max_id = (SELECT MAX(id) FROM old_table);
SET @start = 1;
WHILE @start <= @max_id DO
START TRANSACTION;
INSERT INTO new_table SELECT * FROM old_table
WHERE id >= @start AND id < @start + @batch_size;
COMMIT;
SET @start = @start + @batch_size;
-- 可選:SLEEP(0.1) 降低主從延遲壓力
END WHILE;
-- 4. 驗證行數一致
SELECT COUNT(*) FROM old_table;
SELECT COUNT(*) FROM new_table;
-- 5. 切換 (需短暫鎖表)
LOCK TABLES old_table WRITE, new_table WRITE;
-- 處理增量 (若有)
INSERT INTO new_table SELECT * FROM old_table WHERE id > @max_id;
RENAME TABLE old_table TO old_table_backup, new_table TO old_table;
UNLOCK TABLES;
| 維度 | ALTER TABLE | Dump/Import | CREATE+INSERT |
|---|---|---|---|
| 操作複雜度 | 低 | 中 | 高 |
| 鎖表時間 | 極長 (全程) | 短 (僅匯入末期) | 極短 (僅最終 RENAME) |
| 磁碟空間 | 1x | 2x+ | 2x |
| 可中斷恢復 | 否 | 是 (重新匯入) | 是 (續傳批次) |
| 結構調整 | 否 | 是 | 是 |
| 引擎特性遺失 | 是 | 可手動保留 | 可手動保留 |
ANALYZE TABLE 更新統計資訊pt-online-schema-change (Percona Toolkit) 可實現真正線上無鎖轉換