您好,登錄后才能下訂單哦!
MySQL從5.6.17以后,支持在線修改表結構操作(online ddl),即在變更表結構的過程中,不阻塞dml和dql操作.
根據操作過程中是否需要表拷貝,online ddl可分為下面兩大類:
1.需要表拷貝的 ddl 操作:
增加、刪除、重排列。
增加、刪除主鍵。
改變表的 ROW_FORMAT 或 KEY_BLOCK_SIZE屬性。
改變的字段的null狀態。
執行OPTIMIZE TABLE,優化表。
使用 FORCE 選項重建表。
使用ALTER TABLE ... ENGINE=INNODB 語句。
首次創建全文索引。
2.不需要表拷貝的 ddl 操作:
創建、增加、刪除普通索引。
創建第二個及后續的全文索引。
為字段設置默認值。
改變auto-increment值。
刪除外鍵約束。
添加外鍵約束( 只有在foreign_key_checks=off時)
僅僅改變列的名稱
設置表的持續統計選項(STATS_PERSISTENT, STATS_AUTO_RECALC STATS_SAMPLE_PAGES)
特別說明:全文索引需要特別注意,創建了全文索引的表基本上不支持在線ddl操作。
ySQL 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之前確保沒有大事務在執行,否則一樣出現連環鎖表。
從上面的介紹可以看出,不是5.6支持在線ddl就可以隨心所欲的alter table,鎖不鎖表要看情況:
提示:下表根據官方 Summary of Online Status for DDL Operations 整理挑選的常用操作。
In-Place為Yes是優選項,說明該操作支持INPLACE
Copies Table為No是優選項,因為為Yes需要重建表。大部分情況與In-Place是相反的
Allows Concurrent DML?為Yes是優選項,說明ddl期間表依然可讀寫,可以指定 LOCK=NONE(如果操作允許的話mysql自動就是NONE)
Allows Concurrent Query?默認所有DDL操作期間都允許查詢請求,放在這只是便于參考
Notes會對前面幾列Yes/No帶*
號的限制說明
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:
添加、刪除列,改變列順序
添加或刪除主鍵
改變行格式ROW_FORMAT和壓縮塊大小KEY_BLOCK_SIZE
改變列NULL或NOT NULL
優化表OPTIMIZE TABLE
強制 rebuild 該表
不允許并發DML的情況有:修改列數據類型、刪除主鍵、變更表字符集,即這些類型操作ddl是不能online的。
另外,更改主鍵索引與普通索引處理方式是不一樣的,主鍵即聚集索引,體現了表數據在物理磁盤上的排列,包含了數據行本身,需要拷貝表;而普通索引通過包含主鍵列來定位數據,所以普通索引的創建只需要一次掃描主鍵即可,而且是在已有數據的表上建立二級索引,更緊湊,將來查詢效率更高。
修改主鍵也就意味著要重建所有的普通索引。刪除二級索引更簡單,修改InnoDB系統表信息和數據字典,標記該所以不存在,標記所占用的表空間可以被新索引或數據行重新利用。
MySQL5.6幾種建索引方式比較。
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.17 |
+-----------+
mysql> CREATE TABLE test AS SELECT * FROM information_schema.columns;
mysql> INSERT INTO test SELECT * FROM test;
mysql> INSERT INTO test SELECT * FROM test;
mysql> SELECT COUNT(1) FROM test;
+----------+
| COUNT(1) |
+----------+
| 312928 |
+----------+
1 row in set (0.17 sec)
ALGORITHM=inplace,就地進行,如果允許的話則修改操作可以直接在該表上執行。
mysql> CREATE INDEX ind_t_column_name ON test(column_name) ALGORITHM=inplace;
Query OK, 0 rows affected (1.54 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE test DROP INDEX ind_t_column_name;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> CREATE INDEX ind_t_column_name ON test(column_name);
Query OK, 0 rows affected (1.70 sec)
Records: 0 Duplicates: 0 Warnings: 0
ALGORITHM=copy,用于標識改操作是否需要整個表。
mysql> CREATE INDEX ind_t_column_name ON test(column_name) ALGORITHM=copy;
Query OK, 312928 rows affected (5.93 sec)
Records: 312928 Duplicates: 0 Warnings: 0
注:
SET old_alter_table=0; --ALGORITHM=inplace
SET old_alter_table=1; --ALGORITHM=copy
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。