在 MySQL 5.1 (帶InnoDB Plugin)和5.5中,有個新特性叫 Fast Index Creation(下稱 FIC),就是在添加或者刪除二級索引的時候,能夠不用複製原表。對於以前的版本對於索引的添加刪除這類DDL操做,MySQL數據庫的操做過程爲以下:html
爲了保持數據的一致性,中間複製數據(Copy Table)全程鎖表只讀,若是有寫請求進來將沒法提供服務,鏈接數爆張。mysql
引入FIC以後,建立二級索引時會對原表加上一個S鎖,建立過程不須要重建表(no-rebuild);刪除InnoDB二級索引只須要更新內部視圖,並標記這個索引的空間可用,去掉數據庫元數據上該索引的定義便可。這個過程也只容許讀操做,不能寫入,但大大加快了修改索引的速度(不含主鍵索引,InnoDB IOT的特性決定了修改主鍵依然須要 Copy Table )。sql
FIC只對索引的建立刪除有效,MySQL 5.6 Online DDL把這種特性擴展到了添加列、刪除列、修改列類型、列重命名、設置默認值等等,實際效果要看所使用的選項和操做類別來定。數據庫
MySQL 在線DDL分爲 INPLACE
和 COPY
兩種方式,經過在ALTER語句的ALGORITHM參數指定。緩存
ALGORITHM=INPLACE
,能夠避免重建錶帶來的IO和CPU消耗,保證ddl期間依然有良好的性能和併發。ALGORITHM=COPY
,須要拷貝原始表,因此不容許併發DML寫操做,可讀。這種copy方式的效率仍是不如 inplace ,由於前者須要記錄undo和redo log,並且由於臨時佔用buffer pool引發短期內性能受影響。上面只是 Online DDL 內部的實現方式,此外還有 LOCK 選項控制是否鎖表,根據不一樣的DDL操做類型有不一樣的表現:默認mysql儘量不去鎖表,可是像修改主鍵這樣的昂貴操做不得不選擇鎖表。併發
LOCK=NONE
,即DDL期間容許併發讀寫涉及的表,好比爲了保證 ALTER TABLE 時不影響用戶註冊或支付,能夠明確指定,好處是若是不幸該 alter語句不支持對該表的繼續寫入,則會提示失敗,而不會直接發到庫上執行。ALGORITHM=COPY
默認LOCK級別LOCK=SHARED
,即DDL期間表上的寫操做會被阻塞,但不影響讀取。LOCK=DEFAULT
,讓mysql本身去判斷lock的模式,原則是mysql儘量不去鎖表LOCK=EXCLUSIVE
,即DDL期間該表不可用,堵塞任何讀寫請求。若是你想alter操做在最短的時間內完成,或者表短期內不可用能接受,能夠手動指定。可是有一點須要說明,不管任何模式下,online ddl開始以前都須要一個短期排它鎖(exclusive)來準備環境,因此alter命令發出後,會首先等待該表上的其它操做完成,在alter命令以後的請求會出現等待waiting meta data lock
。一樣在ddl結束以前,也要等待alter期間全部的事務完成,也會堵塞一小段時間。因此儘可能在ALTER TABLE以前確保沒有大事務在執行,不然同樣出現連環鎖表。app
從上面的介紹能夠看出,不是5.6支持在線ddl就能夠爲所欲爲的alter table,鎖不鎖表要看狀況:less
提示:下表根據官方 Summary of Online Status for DDL Operations 整理挑選的經常使用操做。性能
Operation | In-Place? | Copies Table? | Allows Concurrent DML? | Allows Concurrent Query? | Notes |
---|---|---|---|---|---|
添加索引 | Yes* | No* | Yes | Yes | 對全文索引的一些限制 |
刪除索引 | Yes | No | Yes | Yes | 僅修改表的元數據 |
OPTIMIZE TABLE | Yes | Yes | Yes | Yes | 從 5.6.17開始使用ALGORITHM=INPLACE,固然若是指定了old_alter_table=1 或mysqld啓動帶--skip-new 則將仍是COPY模式。若是表上有全文索引只支持COPY |
對一列設置默認值 | Yes | No | Yes | Yes | 僅修改表的元數據 |
對一列修改auto-increment 的值 | Yes | No | Yes | Yes | 僅修改表的元數據 |
添加 foreign key constraint | Yes* | No* | Yes | Yes | 爲了不拷貝表,在約束建立時會禁用foreign_key_checks |
刪除 foreign key constraint | Yes | No | Yes | Yes | foreign_key_checks 不影響 |
改變列名 | Yes* | No* | Yes* | Yes | 爲了容許DML併發, 若是保持相同數據類型,僅改變列名 |
添加列 | Yes* | Yes* | Yes* | Yes | 儘管容許 ALGORITHM=INPLACE ,但數據大幅重組,因此它仍然是一項昂貴的操做。當添加列是auto-increment,不容許DML併發 |
刪除列 | Yes | Yes* | Yes | Yes | 儘管容許 ALGORITHM=INPLACE ,但數據大幅重組,因此它仍然是一項昂貴的操做 |
修改列數據類型 | No | Yes* | No | Yes | 修改類型或添加長度,都會拷貝表,並且不容許更新操做 |
更改列順序 | Yes | Yes | Yes | Yes | 儘管容許 ALGORITHM=INPLACE ,但數據大幅重組,因此它仍然是一項昂貴的操做 |
修改ROW_FORMAT 和KEY_BLOCK_SIZE |
Yes | Yes | Yes | Yes | 儘管容許 ALGORITHM=INPLACE ,但數據大幅重組,因此它仍然是一項昂貴的操做 |
設置列屬性NULL 或NOT NULL |
Yes | Yes | Yes | Yes | 儘管容許 ALGORITHM=INPLACE ,但數據大幅重組,因此它仍然是一項昂貴的操做 |
添加主鍵 | Yes* | Yes | Yes | Yes | 儘管容許 ALGORITHM=INPLACE ,但數據大幅重組,因此它仍然是一項昂貴的操做。 若是列定義必須轉化NOT NULL,則不容許INPLACE |
刪除並添加主鍵 | Yes | Yes | Yes | Yes | 在同一個 ALTER TABLE 語句刪除就主鍵、添加新主鍵時,才容許inplace;數據大幅重組,因此它仍然是一項昂貴的操做。 |
刪除主鍵 | No | Yes | No | Yes | 不容許併發DML,要拷貝表,並且若是沒有在同一 ATLER TABLE 語句裏同時添加主鍵則會收到限制 |
變動表字符集 | No | Yes | No | Yes | 若是新的字符集編碼不一樣,重建表 |
從表看出,In-Place爲No,DML必定是No,說明 ALGORITHM=COPY
必定會發生拷貝表,只讀。但 ALGORITHM=INPLACEE
也要可能發生拷貝表,但能夠併發DML:優化
不容許併發DML的狀況有:修改列數據類型、刪除主鍵、變動表字符集,即這些類型操做ddl是不能online的。
另外,更改主鍵索引與普通索引處理方式是不同的,主鍵即彙集索引,體現了表數據在物理磁盤上的排列,包含了數據行自己,須要拷貝表;而普通索引經過包含主鍵列來定位數據,因此普通索引的建立只須要一次掃描主鍵便可,並且是在已有數據的表上創建二級索引,更緊湊,未來查詢效率更高。
修改主鍵也就意味着要重建全部的普通索引。刪除二級索引更簡單,修改InnoDB系統表信息和數據字典,標記該因此不存在,標記所佔用的表空間能夠被新索引或數據行從新利用。
datadir
目錄有足夠的磁盤空間,可以放的下整張表,由於拷貝表的的操做是直接在數據目錄下進行的。tmpdir
目錄足夠存下索引一列的數據(若是是組合索引,當前臨時排序文件一合併到原表上就會刪除)innodb_online_alter_log_max_size
變量所指定的大小,會引發 DB_ONLINE_LOG_TOO_BIG 錯誤。默認爲 128M,特別對於須要拷貝大表的alter操做,考慮臨時加大該值,以此得到更大的日誌緩存空間ALTER TABLE
以後,最好 ANALYZE TABLE tb1
去更新索引統計信息online ddl主要包括3個階段,prepare階段,ddl執行階段,commit階段,rebuild方式比no-rebuild方式實質多了一個ddl執行階段,prepare階段和commit階段相似。下面將主要介紹ddl執行過程當中三個階段的流程。
Prepare階段 :
ddl執行階段 :
commit階段 :
1、打開功能
mysql> UPDATE setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'stage/innodb/alter%'; Query OK, 7 rows affected (0.00 sec) Rows matched: 7 Changed: 7 Warnings: 0 mysql> UPDATE setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE '%stages%'; Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0
2、執行改表操做
mysql> ALTER TABLE employees.employees ADD COLUMN middle_name varchar(14) AFTER first_name; Query OK, 0 rows affected (9.27 sec) Records: 0 Duplicates: 0 Warnings: 0
3、查看改表進度
mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED FROM events_stages_current; +------------------------------------------------------+----------------+----------------+ | EVENT_NAME | WORK_COMPLETED | WORK_ESTIMATED | +------------------------------------------------------+----------------+----------------+ | stage/innodb/alter table (read PK and internal sort) | 280 | 1245 | +------------------------------------------------------+----------------+----------------+ 1 row in set (0.01 sec)