| 方式 | 版本 | 原理 | 讀可用 | 寫可用 | 空間開銷 | 鎖表時間 |
|---|---|---|---|---|---|---|
| Copy Table | 早期 | 建臨時表拷貝數據再 Rename | 是 | 否 | 1倍數據量 | 整個過程 |
| Inplace | 5.5 / Plugin | 原表直接構建索引,無臨時表 | 是 | 否 | 極小 | 構建過程全程 |
| Online | 5.6.7+ | Inplace + Row Log 記錄增量變更,末尾重放 | 是 | 是 | 極小 | 僅重放最後一個 Block 時短暫鎖表 |
ALTER TABLE t1 ADD INDEX idx_t1_b(b);
mysql_alter_table() 判斷是否支持 Inplace(不支持場景:自增列修改、列重命名、行格式變更等)。add_index() -> row_merge_create_index() 創建索引數據字典,記錄創建事務 trx_id。wait_while_table_is_used() 等待所有只讀事務提交(防止老事務用無版本信息的新索引導致快照讀錯誤)。final_add_index() 清理收尾。trx_id:標識創建事務。比它更老的活躍事務嘗試用新索引做快照讀時,直接報錯 ERROR 1412: Table definition has changed。ALTER TABLE t1 ADD INDEX idx_t1_b(b);
ONLINE_INDEX_CREATION。innodb_sort_buffer_size 控制),記錄構建過程中發生的 DML(INSERT/DELETE_MARK 等)。ONLINE_INDEX_COMPLETE,新 DML 直接寫入索引,無需 Row Log。row_merge_dup_t 記錄衝突,若發現重複鍵則創建失敗(早期版本存在 Bug,見下)。trx_id 更新為 Row Log 中最大事務 ID,所有更早事務均不可用新索引。並發場景下,UPDATE 導致唯一鍵衝突時,Row Log 重放邏輯漏判,導致唯一索引創建成功但表中實際存在重複值。生產環境升級前請充分測試。
posix_fadvise(fd, offset, len, POSIX_FADV_DONTNEED):釋放文件在 Page Cache 中的干淨頁,避免大文件操作污染緩存。fallocate(fd, FALLOC_FL_PUNCH_HOLE, offset, len):打洞釋放磁盤空間,適用於稀疏文件管理。