1. 程式人生 > >MySQL5.7—在線DDL總結

MySQL5.7—在線DDL總結

mysql 在線 ddl

---切記:DDL操作要在業務低峰期進行


1、MySQL各版本,對於DDL的處理方式是不同的,主要有三種:


①:Copy Table方式: 這是InnoDB最早支持的方式。顧名思義,通過臨時表拷貝的方式實現的。新建一個帶有新結構的臨時表,將原表數據全部拷貝到臨 時表,然後Rename,完成創建操作。這個方式過程中,原表是可讀的,不可寫。但是會消耗一倍的存儲空間。

②:Inplace方式:這是原生MySQL 5.5,以及innodb_plugin中提供的方式。所謂Inplace,也就是在原表上直接進行,不會拷貝臨時表。相對於Copy Table方式,這比較高效率。原表同樣可讀的,但是不可寫。

③:Online方式:這是MySQL 5.6以上版本中提供的方式,也是今天我們重點說明的方式。無論是Copy Table方式,還是Inplace方式,原表只能允許讀取, 不可寫。對應用有較大的限制,因此MySQL最新版本中,InnoDB支持了所謂的Online方式DDL。與以上兩種方式相比,online方式支持DDL時不僅可 以讀,還可以寫,對於dba來說,這是一個非常棒的改進。


2、MySQL5.7中online ddl:(algorithm=inplace)


ALGORITHM=INPLACE,可以避免重建表帶來的IO和CPU消耗,保證ddl期間依然有良好的性能和並發。 -----****


ALGORITHM=COPY,需要拷貝原始表,所以不允許並發DML寫操作,可讀。這種copy方式的效率還是不如 inplace ,因為前者需要記錄undo和redo log,而且因為臨時占用buffer pool引起短時間內性能受影響。


①:In-Place為Yes是優選項,說明該操作支持INPLACE

②:Copies Table為No是優選項,因為為Yes需要重建表。大部分情況與In-Place是相反的

③:Allows Concurrent DML?為Yes是優選項,說明ddl期間表依然可讀寫,可以指定 LOCK=NONE(如果操作允許的話mysql自動就是NONE)

④:Allows Concurrent Query?默認所有DDL操作期間都允許查詢請求,放在這只是便於參考


二、在線DDL的限制

1)在alter table時,如果涉及到table copy操作,要確保datadir目錄有足夠的磁盤空間,能夠放的下整張表,因為拷貝表的的操作是直接在數據目錄下進行的。

2)添加索引無需table copy,但要確保tmpdir目錄足夠存下索引一列的數據(如果是組合索引,當前臨時排序文件一合並到原表上就會刪除) 3)在主從環境下,主庫執行alter命令在完成之前是不會進入binlog記錄事件,如果允許dml操作則不影響記錄時間,所以期間不會導致延遲。然而,由於從庫是單個SQL Thread按順序應用relay log,輪到ALTER語句時直到執行完才能下一條,所以從庫會在master ddl完成後開始產生延遲。(pt-osc可以控制延遲時間,所以這種場景下它更合適)

4)During each online DDL ALTER TABLE statement, regardless of the LOCK clause, there are brief periods at the beginning and end requiring an exclusive lock on the table (the same kind of lock specified by the LOCK=EXCLUSIVE clause). Thus, an online DDL operation might wait before starting if there is a long-running transaction performing inserts, updates, deletes, or SELECT … FOR UPDATE on that table; and an online DDL operation might wait before finishing if a similar long-running transaction was started while the ALTER TABLE was in progress.

5)在執行一個允許並發DML在線 ALTER TABLE時,結束之前這個線程會應用 online log 記錄的增量修改,而這些修改是其它thread裏產生的,所以有可能會遇到重復鍵值錯誤(ERROR 1062 (23000): Duplicate entry)。

6)涉及到table copy時,目前還沒有機制限制暫停ddl,或者限制IO閥值 7)在MySQL 5.7.6開始能夠通過 performance_schema 觀察alter table的進度

一般來說,建議把多個alter語句合並在一起進行,避免多次table rebuild帶來的消耗。但是也要註意分組,比如需要copy table和只需inplace就能完成的,應該分兩個alter語句。

8)如果DDL執行時間很長,期間又產生了大量的dml操作,以至於超過了innodb_online_alter_log_max_size變量所指定的大小,會引起DB_ONLINE_LOG_TOO_BIG 錯誤。默認為 128M,特別對於需要拷貝大表的alter操作,考慮臨時加大該值,以此獲得更大的日誌緩存空間

9)執行完 ALTER TABLE 之後,最好 ANALYZE TABLE tb1 去更新索引統計信息


三、Online DDL的實現過程

online ddl主要包括3個階段,prepare階段,ddl執行階段,commit階段,rebuild方式比no-rebuild方式實質多了一個ddl執行階段,prepare階段和commit階段類似。下面將主要介紹ddl執行過程中三個階段的流程。


3.1、Prepare階段:

①:創建新的臨時frm文件(與InnoDB無關) ②:持有EXCLUSIVE-MDL鎖,禁止讀寫 ③:根據alter類型,確定執行方式(copy,online-rebuild,online-norebuild)

假如是Add Index,則選擇online-norebuild即INPLACE方式

④:更新數據字典的內存對象

⑤:分配row_log對象記錄增量(僅rebuild類型需要) ⑥:生成新的臨時ibd文件(僅rebuild類型需要)

3.2、ddl執行階段:

①:降級EXCLUSIVE-MDL鎖,允許讀寫

②:掃描old_table的聚集索引每一條記錄rec ③:遍歷新表的聚集索引和二級索引,逐一處理

④:根據rec構造對應的索引項

⑤:將構造索引項插入sort_buffer塊排序 ⑥:將sort_buffer塊更新到新的索引上 ⑦:記錄ddl執行過程中產生的增量(僅rebuild類型需要) ⑧:重放row_log中的操作到新索引上(no-rebuild數據是在原表上更新的) ⑨:重放row_log間產生dml操作append到row_log最後一個Block

3.3、commit階段:

①:當前Block為row_log最後一個時,禁止讀寫,升級到EXCLUSIVE-MDL鎖 ②:重做row_log中最後一部分增量 ③:更新innodb的數據字典表 ④:提交事務(刷事務的redo日誌) ⑤:修改統計信息 ⑥:rename臨時idb文件,frm文件 ⑦:變更完成


---mysql5.7官方文檔說明:

15.13.1 Online DDL Overview
The online DDL feature enhances many DDL operations that formerly required a table copy or blocked
DML operations on the table, or both.
Table 15.10, “Online Status for DDL Operations” shows how the
online DDL feature applies to each DDL statement.
With the exception of
ALTER TABLE partitioning clauses, online DDL operations for partitioned
InnoDB tables follow the same rules that apply to regular InnoDB tables. For more information, see
Section 15.13.7, “Online DDL for Partitioned Tables”.
Some factors affect the performance, space usage, and semantics of online DDL operations. For more
information, see
Section 15.13.8, “Online DDL Limitations”.
The “In-Place?” column shows which operations permit the
ALGORITHM=INPLACE clause.
The “Rebuilds Table?” column shows which operations rebuild the table. For operations that use
the
INPLACE algorithm, the table is rebuilt in place. For operations that do not support the INPLACE
algorithm, the table copy method is used to rebuild the table.
The “Permits Concurrent DML?” column shows which operations are performed fully online. You can
specify
LOCK=NONE to assert that concurrent DML is permitted during the DDL operation. MySQL
automatically permits concurrent DML when possible.
Concurrent queries are permitted during all online DDL operations. You can specify
LOCK=SHARED
to assert that concurrent queries are permitted during a DDL operation. MySQL automatically permits
concurrent queries when possible.
The “Notes” column provides additional information and explains exceptions and dependencies related
to the “Yes/No” values of other columns. An asterisk indicates an exception or dependency

官方文檔地址:

https://dev.mysql.com/doc/refman/5.7/en/innodb-create-index-overview.html


#####################################################################


實驗總結如下:

1、實驗環境是MySQL5.7.18

[[email protected] ~]$ mysql -u root -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.7.18-log MySQL Community Server (GPL)
Copyright (c) 2000, 2014, Oracle, MariaDB Corporation Ab and others.
Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement.

2、創建測試表test_emp,並插入數據

MySQL [(none)]> create database test;
Query OK, 1 row affected (0.07 sec)
MySQL [(none)]> use test
Database changed
MySQL [test]> create table test_emp( id int(10) unsigned NOT NULL AUTO_INCREMENT, c1 int(10) NOT NULL DEFAULT ‘0‘,
    ->  c2 int(10) unsigned DEFAULT NULL, c5 int(10) unsigned NOT NULL DEFAULT ‘0‘, c3 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    -> c4 varchar(200) NOT NULL DEFAULT ‘‘, PRIMARY KEY(id), KEY idx_c1(c1), KEY idx_c2(c2) )ENGINE=InnoDB ;
Query OK, 0 rows affected (0.11 sec)   ----創建測試表:test_emp
MySQL [test]> delimiter //
MySQL [test]> create procedure insert_test_emp(in row_num int )
    -> begin
    ->  declare i int  default 0;
    ->  while i < row_num do
    -> insert into test_emp(c1, c2, c5,c3, c4) values( floor(rand()*row_num),floor(rand()*row_num),floor(rand()*row_num),now(),repeat(‘su‘, floor(rand()*20)));
    -> set i = i+1;
    ->  END while;
    -> end
    -> //
Query OK, 0 rows affected (0.01 sec)
MySQL [test]> 
MySQL [test]> call insert_test_emp(100000);   ----向測試表test_emp插入數據
Query OK, 1 row affected (8 min 24.34 sec)
MySQL [test]> desc test_emp;
+-------+------------------+------+-----+-------------------+-----------------------------+
| Field | Type             | Null | Key | Default           | Extra                       |
+-------+------------------+------+-----+-------------------+-----------------------------+
| id    | int(10) unsigned | NO   | PRI | NULL              | auto_increment              |
| c1    | int(10)          | NO   | MUL | 0                 |                             |
| c2    | int(10) unsigned | YES  | MUL | NULL              |                             |
| c5    | int(10) unsigned | NO   |     | 0                 |                             |
| c3    | timestamp        | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| c4    | varchar(200)     | NO   |     |                   |                             |
+-------+------------------+------+-----+-------------------+-----------------------------+
6 rows in set (0.00 sec)
MySQL [test]>

3、在線修改字段:

MySQL [test]> alter table test_emp add c6 varchar(60) not null default ‘‘;
Query OK, 0 rows affected (2.04 sec)
Records: 0  Duplicates: 0  Warnings: 0
MySQL [test]> select count(*) from test_emp;
+----------+
| count(*) |
+----------+
|   100000 |
+----------+
1 row in set (0.02 sec)
MySQL [test]> ---使用ALGORITHM=INPLACE選項在線修改
MySQL [test]> alter table test_emp ALGORITHM=INPLACE,modify c6 varchar(80) not null default ‘‘;
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0
MySQL [test]>


----可以看到 執行時間為0.09秒,執行速度很快


不過,ALGORITHM用法只對varcahr類型有效哦,比如我們對c1列int型進行變更:

MySQL [test]> alter table test_emp ALGORITHM=INPLACE,modify c1 int(11) unsigned not null;

ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

MySQL [test]>


---註意:

①:只變更int的位數,是可以的,不過這沒什麽意義,因為無論你int多少,最多都只能存10位,這也就是為什麽我們生產庫開發規範要定義所有的int都用int(10)。


②:如果字段屬性大於並等於varchar(256)(這裏的256是指字節(UTF8占用3字節)或者把varchar(80)減少到varchar(70)或者更少),則仍需要拷貝數據且鎖全表。

mysql> alter table test_emp ALGORITHM=INPLACE,modify c6 varchar(84) not null default ‘‘;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
mysql> alter table test_emp ALGORITHM=INPLACE,modify c6 varchar(85) not null default ‘‘;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
mysql> alter table test_emp ALGORITHM=INPLACE,modify c6 varchar(86) not null default ‘‘;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
 
mysql> alter table test_emp ALGORITHM=INPLACE,modify c6 varchar(40) not null default ‘‘;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
 
mysql> alter table test_emp ALGORITHM=INPLACE,modify c6 varchar(70) not null default ‘‘;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.

註意:添加字段alter table時,對該表的增刪改查均不會鎖表。而在這之前,當該表被訪問時,需要等其執行完畢後才可以執行alter table。


總結:

在varchar變更字段長度方面,5.7的新特性ALGORITHM參數可以快速調整varchar類型的字段長度。5.7同5.6一樣,增加,刪除字段或索引不鎖全表,刪除主鍵鎖全表。因此,在上線時,一定要執行show processlist命令並觀察,此刻是否有某個慢SQL對該表進行操作,以免alter table表時出現鎖表現象。


*********************************************************************************

1、在線添加索引:

alter table test_emp add index idx_id (c1),ALGORITHM=INPLACE;


2、在線添加字段:

alter table test_emp add name varchar(100) not null default ‘‘,ALGORITHM=INPLACE;


3、在線修改字段屬性:

alter table test_emp ALGORITHM=INPLACE,modify c6 varchar(85) not null default ‘‘;


語法:

1.PRIMARY KEY(主鍵索引)

mysql>ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) ,ALGORITHM=INPLACE;


2.UNIQUE(唯一索引)

mysql>ALTER TABLE `table_name` ADD UNIQUE (`column` ) ,ALGORITHM=INPLACE;

3.INDEX(普通索引)

mysql>ALTER TABLE `table_name` ADD INDEX index_name ( `column` ),ALGORITHM=INPLACE;


4.FULLTEXT(全文索引)

mysql>ALTER TABLE `table_name` ADD FULLTEXT ( `column` ),ALGORITHM=INPLACE;


5.多列索引

mysql>ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` ),ALGORITHM=INPLACE;


註意:

在MySQL5.6中在線DDL會鎖全表:增加、刪除字段或索引不會鎖全表,刪除主鍵會鎖全表。


本文出自 “笨小孩的dba之路” 博客,請務必保留此出處http://fengfeng688.blog.51cto.com/4896812/1956827

MySQL5.7—在線DDL總結