索引的添加MySQL經歷了一下幾個歷程:
一 .在MySQL 5.5版本之前,添加索引具體是這樣的:
1.首先創建一張臨時表和原表數據結構相同,將你要添加的索引加上。
2.把原表數據導入臨時表。
3.刪除原表。
4.將臨時表重命名為原表。
這樣做有很大問題:
首先對於大數據量的導入需要很長的時間,那么在這段時間里新增或修改的數據沒辦法處理。
其次如果碰上大事務正在新增或更新更新這張原表還會鎖表,你還沒辦法用sql去導入到臨時表中。
二 .但在InnoDB 1.0版本開始,支持一種Fast Index(快速索引創建)的方式,簡稱FIC,他是這樣做的:
對於輔助索引的創建,他不需要建臨時表,他會直接將原表加S鎖,這樣就不會有數據導入的問題。
但還是會有些其他問題:
這意味着這加索引的這段時間里這張表只能讀,不能增刪改。而且不適用主鍵索引。
三. 針對一,二階段的問題,Facebook總結並實現了一種在線執行方案-OSC:
1.初始化,檢查原表所有的問題,包括主鍵,觸發器,外鍵等。
2.創建臨時表,添加索引字段。
3.創建deltas表,為下一步創建觸發器做准備。
4.對原表創建增刪改的觸發器,觸發器產生的草所記錄寫入到上一步創建的deltas表。
5.開始OSC操作的事務。
6.刪除所有輔助索引,再將原表數據通過分片文件寫入臨時表。
7.將deltas表中產生的記錄應用到臨時表中。
8.重新創建輔助索引。
10.將原表和臨時表交換名字,在這個過程中會鎖表,但這個過程很快。
以上便是整個OSC過程,看起來就很復雜,實際的腳本也很復雜,光是核心PHP代碼就2000多行,而且有一定局限性,對於分布式無法主從同步。
四.MySQL5.6版本開始支持在線創建--Online DDL,只需一行代碼:
以下是對輔助索引的添加:
ALTER TABLE table_name ADD INDEX indea_name ,ALGORITHM=INPLACE,LOCK=NONE;
ALGORITHM指定創建或刪除索引得算法,有以下幾類:
COPY:按照5.1之前的版本,創建臨時表的方式。
INPLACE:不需要創建臨時表。
DEFAULT:表示根據參數old_alter_table來判斷是用COPY還是INPLACE,默認OFF,表示采用INPLACE方式。
LOCK表示加鎖情況:
NONE:不添加任何鎖,允許並發。
SHARE:加S鎖。
EXCLUSIVE:加X鎖,讀寫都不允許。
DEFAULT:會先判斷是否可用NONE,若不能再判斷是否可用SHARE模式,最后判斷EXCLUSIVE。
Online DDL的原理是則好樣的:
1.在創建或刪除索引的同時,會將這段時間發生的增刪改操作的日志寫入一個緩存中,待完成索引后再重新將日志應用到表上,達到數據一致性。這個緩存的小由innodb_online_alter_log_max_size控制,默認128MB。可以根據情況調整。
需要注意的是,在這個過程中,sql不會用到正在創建的索引。