ALTER TABLE 是 MySQL DDL 核心操作,涉及鎖表、重建表、線上 DDL (Online DDL) 等效能考量。本文提供四大類常用操作標準語法、MySQL 5.6/5.7/8.0 線上 DDL 支援差異、大表操作最佳實踐。
-- 基本語法
ALTER TABLE table_name ADD column_name column_definition [FIRST | AFTER existing_column];
-- 範例:在 id 後增加 username VARCHAR(20) NOT NULL DEFAULT ''
ALTER TABLE user_info ADD username VARCHAR(20) NOT NULL DEFAULT '' AFTER id;
-- 批次增加多欄位 (單次重建表)
ALTER TABLE user_info
ADD email VARCHAR(100) NOT NULL DEFAULT '' AFTER username,
ADD phone VARCHAR(20) NOT NULL DEFAULT '' AFTER email,
ADD status TINYINT UNSIGNED NOT NULL DEFAULT 1 AFTER phone;
-- 基本語法
ALTER TABLE table_name DROP COLUMN column_name;
-- 範例
ALTER TABLE user_info DROP COLUMN phone;
-- 批次刪除
ALTER TABLE user_info DROP COLUMN email, DROP COLUMN status;
-- 語法:必須重新指定完整欄位定義
ALTER TABLE table_name CHANGE old_name new_name column_definition;
-- 範例:id -> user_id,並保持 INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
ALTER TABLE user_info CHANGE id user_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
-- 語法:不改名稱,僅改定義
ALTER TABLE table_name MODIFY column_name new_column_definition;
-- 範例:username VARCHAR(20) -> VARCHAR(50) NOT NULL DEFAULT ''
ALTER TABLE user_info MODIFY username VARCHAR(50) NOT NULL DEFAULT '';
-- 修改為 NOT NULL (需確保現有資料無 NULL)
ALTER TABLE user_info MODIFY email VARCHAR(100) NOT NULL DEFAULT '';
| 操作 | 5.6 | 5.7 | 8.0 | 備註 |
|---|---|---|---|---|
| ADD COLUMN (末尾) | INPLACE | INPLACE | INSTANT | 8.0 秒級,無鎖、無重建 |
| ADD COLUMN (中間/指定位置) | COPY | INPLACE | INPLACE | 5.6 需重建表 |
| DROP COLUMN | COPY | INPLACE | INPLACE | 5.6 需重建表 |
| CHANGE COLUMN (改名+定義) | COPY | INPLACE | INPLACE | |
| MODIFY COLUMN (類型/長度/預設值) | COPY | INPLACE | INSTANT* | 8.0 部分類型變更支援 INSTANT (如擴大 VARCHAR、修改 DEFAULT) |
| ADD INDEX | INPLACE | INPLACE | INPLACE | 可並行讀寫,建立過程有短暫排他鎖 |
| DROP INDEX | INPLACE | INPLACE | INSTANT |
INSTANT:僅修改數據字典,無鎖、無重建、毫秒級。
INPLACE:在原表重建,允許並行 DML,短暫排他鎖。
COPY:建立臨時表複製資料,全程排他鎖,**大表嚴禁**。
EXPLAIN ALTER TABLE ... (8.0.18+) 查看 alter_table_algorithm。pt-online-schema-change --alter "ADD COLUMN status TINYINT DEFAULT 1" \
D=db,t=user_info --execute --max-load Threads_running=100 --critical-load Threads_running=200
觸發器同步、分塊複製、可暫停/恢復、**零停機**。tmpdir 可指定大分區)。SHOW PROCESSLIST 觀察 State: copy to tmp table / alter table。DROP FOREIGN KEY,變更後重建。| 錯誤 | 原因 | 解決 |
|---|---|---|
ERROR 1025 (HY000): Error on rename | 外鍵約束衝突、臨時表名衝突 | 先刪除外鍵、檢查 innodb_tmpdir 空間 |
ERROR 1118 (42000): Row size too large | 單行超過 65535 bytes (含變長欄位溢位頁) | 拆分大欄位至獨立表、使用 BLOB/TEXT |
LOCK WAIT TIMEOUT | 大表 COPY 算法長時間持有排他鎖 | 改用 pt-osc、升級 5.7+、拆分操作 |
| 主從延遲飆升 | DDL 在主庫執行久,從庫單線程重放 | 從庫設定 slave_parallel_workers、slave_parallel_type=LOGICAL_CLOCK |