對於Online DDL,以前簡單分析了一些場景MySQL中的Online DDL(第一篇)(r11筆記第3天),其實有一個很關鍵的點沒提到,那就是online DDL的算法,目前有三個操做選項,default,inplace,copy可選html
具體能夠參考 https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl.htmlmysql
> select count(*) from newtest;
+----------+
| count(*) |
+----------+
| 22681426 |
+----------+
1 row in set (45.76 sec)表結構信息以下:算法
> show create table newtest\G
*************************** 1. row ***************************
Table: newtest
Create Table: CREATE TABLE `newtest` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`game_type` int(11) NOT NULL DEFAULT '-1' ,
`login_time` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
`login_account` varchar(100) DEFAULT NULL ,
`cn_master` varchar(100) NOT NULL DEFAULT '' ,
`client_ip` varchar(100) DEFAULT '' ,
PRIMARY KEY (`id`),
KEY `ind_tmp_account1` (`login_account`),
KEY `ind_login_time_newtest` (`login_time`)
) ENGINE=InnoDB AUTO_INCREMENT=22681850 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)sql
好比咱們運行下面的SQL,添加一個字段,默認狀況下是使用copy的算法,即數據是平行復制一份。ide
alter table newtest add column newcol varchar(10) default '';這個變動過程會生成兩個臨時的文件.frm,.ibd
-rw-r----- 1 mysql mysql 8840 Dec 5 18:13 newtest.frm
-rw-r----- 1 mysql mysql 4353687552 Dec 5 18:45 newtest.ibd
...
-rw-r----- 1 mysql mysql 8874 Feb 27 22:25 #sql-6273_2980ab.frm
-rw-r----- 1 mysql mysql 41943040 Feb 27 22:25 #sql-ib280-3638407428.ibd
...在這個變動的過程當中,是運行DML操做的,並且沒有任何阻塞。測試
> insert into newtest(game_type,login_time,login_account,cn_master,client_ip) values(1,'2017-02-27 16:22:10','150581500032','572031626','183.128.143.113');
Query OK, 1 row affected (0.05 sec)htm
由於使用了主鍵自增,因此我能夠用一樣的語句再插入一條記錄,也是全然沒有阻塞。索引
> insert into newtest(game_type,login_time,login_account,cn_master,client_ip) values(1,'2017-02-27 16:22:10','150581500032','572031626','183.128.143.113');
Query OK, 1 row affected (0.00 sec)這個時候查看show processlist的結果,相比就顯得有些簡單了。不像以前的版本中會有table metadata lock的字樣了。ip
+---------+-----------------+-----------------------------+----------------+-------------+---------+--------------------------------
|Id | User | Host | db | Command | Time | State
+---------+-----------------+-----------------------------+----------------+-------------+---------+--------------------------------
| 2719915 | root | localhost | test | Query | 75 | altering tablessl
咱們簡單看看上面列舉出來的配置文件.frm
能夠經過strings的方式看到一個基本的結構信息。
# strings newtest.frm
PRIMARY
ind_tmp_account1
ind_login_time_newtest
InnoDB
)
game_type
login_time
login_account
cn_master
client_ip
game_type
login_time
login_account
cn_master
client_ip
而查看臨時建立的.frm文件
# strings "#sql-6273_2980ab.frm"
PRIMARY
ind_tmp_account1
ind_login_time_newtest
InnoDB
)
game_type
login_time
login_account
cn_master
client_ip
newcol
game_type
login_time
login_account
cn_master
client_ip
newcol整個添加字段的操做持續時間爲10分鐘左右。
> alter table newtest add column newcol varchar(10) default '';
Query OK, 0 rows affected (10 min 31.64 sec)
Records: 0 Duplicates: 0 Warnings: 0能夠看到修改後的.ibd文件大小相比要大了一些。
-rw-r----- 1 mysql mysql 8874 Feb 27 22:25 newtest.frm
-rw-r----- 1 mysql mysql 4047503360 Feb 27 22:34 newtest.ibd而若是咱們換一個角度來看,咱們刪除一個字段。
--alter table newtest drop column newcol , ALGORITHM=INPLACE; --這種方式是有問題的,採用以下的方式,咱們聲明使用inplace算法,而實際狀況如何呢。
> alter table newtest drop column newcol , ALGORITHM=INPLACE;
Query OK, 0 rows affected (9 min 54.18 sec)
Records: 0 Duplicates: 0 Warnings: 0咱們能夠看到DML操做暢通無阻。
> insert into newtest(game_type,login_time,login_account,cn_master,client_ip) values(1,'2017-02-27 16:22:10','150581500032','572031626','183.128.143.113');
Query OK, 1 row affected (0.15 sec)這個過程能夠看到效果和啓用copy算法是同樣的,爲何呢。由於添加字段,刪除字段是一個數據重組的過程,因此相比而言,這個操做的代價也是昂貴的。
而後咱們添加索引,啓用inplace算法。
alter table newtest add index (client_ip) ,algorithm=inplace;這個過程就特別了,依舊會建立.frm的臨時文件,可是數據文件不會複製,而是現改。
-rw-r----- 1 mysql mysql 8840 Feb 27 22:49 newtest.frm
-rw-r----- 1 mysql mysql 4018143232 Feb 27 23:06 newtest.ibd
...
-rw-r----- 1 mysql mysql 8840 Feb 27 23:06 #sql-6273_2980ab.frm這個過程當中,DML依舊是暢通的。
> insert into newtest(game_type,login_time,login_account,cn_master,client_ip) values(1,'2017-02-27 16:22:10','150581500032','572031626','183.128.143.113');
Query OK, 1 row affected (0.04 sec)整個添加的過程相比而言,持續時間要短不少,大概是3分鐘左右。
> alter table newtest add index (client_ip) ,algorithm=inplace;
Query OK, 0 rows affected (3 min 42.84 sec)
Records: 0 Duplicates: 0 Warnings: 0
而若是此時刪除索引,這個過程就如同非通常的感受,不到一秒便可完成。
> alter table newtest drop index client_ip ,algorithm=inplace;
Query OK, 0 rows affected (0.13 sec)
Records: 0 Duplicates: 0 Warnings: 0整個過程當中.frm和.ibd文件沒有任何大小變化。
-rw-r----- 1 mysql mysql 8840 Feb 27 23:13 newtest.frm
-rw-r----- 1 mysql mysql 4785700864 Feb 27 23:13 newtest.ibd而若是咱們爲了對比一樣的inpalce和copy操做場景下的代價,可使用copy顯示建立一個索引,便可獲得一個基本的對比狀況。
alter table newtest add index (client_ip) ,algorithm=copy;整個過程由於.ibd文件較大,持續時間也會放大不少,這個環境中執行時間是29分,差異已然很是明顯。
> alter table newtest add index (client_ip) ,algorithm=copy;
Query OK, 22681430 rows affected (29 min 13.80 sec)
Records: 22681430 Duplicates: 0 Warnings: 0
Online DDL仍是存在着一些限定狀況,不少場景尚未徹底測試到,須要結合具體的場景和需求來考量。