第三个问题是在一张两千万的大表上测试发现的,在测试的过程中发现DDL的状态并未处于”Waiting for table metadata lock”,而是开始执行,在查看进程的时候已经是处于”copy to tmp table”状态。 更奇怪的是同样的数据在不同版本的数据库中,实验结果是不一样的。在5.5.28的版本中如上面描述的未出现”Waiting for table metadata lock”,但是在5.6.21版本实验的结果是跟问题一描述得有一般。
我们刚在问题三的MySQL 5.5.28实验中发现session B中的DDL请求并未处于”Waiting for table metadata lock”而是开始执行并处于”copy to tmp table”状态。但是经过前面两个问题的解析,我们就能明白其实并不是session B的DDL没有等待metadata lock加锁,而是加锁是在”rename result table”步骤,处于”copy to tmp table”之后,而前面我们也说了问题三的实验对象是一张两千万行的大表,所以临时表环境耗时很长,因此我们在show processlist的时候发现该进程处于”copy to tmp table”而不是”Waiting for table metadata lock”状态,造成了没有等待加锁的假象,其实继续等待下去,等待临时表生成完毕还是会进入等待加锁状态。
那为什么同样一张大表,在MySQL 5.6.21中却直接进入”Waiting for table metadata lock”呢?我们猜测跟MySQL 5.6的online DDL特性有关,下面我们还是通过profile来验证。
session B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
mysql> show profile;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting |0.000065 |
| checking permissions |0.000004 |
| checking permissions |0.000005 |
| init |0.000003 |
| Opening tables | 0.000035 |
| setup |0.000030 |
| creating table |0.000663 |
| After create | 0.000078 |
| Waiting for table metadata loc | 1.003192 |
| After create | 0.000012 |
| Waiting for table metadata loc | 1.002947 |
| After create | 0.000014 |
| Waiting for table metadata loc | 1.002883 |
| After create | 0.000012 |
| Waiting for table metadata loc | 1.002999 |
| After create | 0.000012 |
| Waiting for table metadata loc | 1.002944 |
| After create | 0.000010 |
| Waiting for table metadata loc | 1.002934 |
| After create | 0.000008 |
| Waiting for table metadata loc | 1.002937 |
| After create | 0.000009 |
| Waiting for table metadata loc | 1.002954 |
| After create | 0.000009 |
| Waiting for table metadata loc | 0.247139 |
| After create | 0.000021 |
| System lock | 0.000015 |
| preparing for alter table |0.001604 |
| altering table |0.785378 |
| committing alter table to stor |0.032014 |
| end |0.000025 |
| query end |0.000154 |
| closing tables |0.000010 |
| freeing items |0.000017 |
| cleaning up |0.000018 |
+--------------------------------+----------+
35 rows in set, 1 warning (0.00 sec)
我们在profile中并未见”copy to tmp table”的步骤,这也就是为什么在一开始测试的5.6.21版本中不会像5.5.28版本那样需要在”copy to tmp table”等待那么久。下面我们关闭掉online DDL特性再来一试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
mysql> set old_alter_table = 1;
QueryOK, 0 rows affected (0.00 sec)
mysql> alter table xxx add xxxid int; //执行DDL
...
mysql> show profile;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000055 |
| checking permissions | 0.000005 |
| checking permissions | 0.000004 |
| init | 0.000002 |
| Opening tables | 0.000034 |
| setup | 0.000035 |
| creating table | 0.000558 |
| After create | 0.000020 |
| System lock | 0.002289 |
| copy to tmp table | 1.039543 |
| rename result table | 0.000017 |
| Waitingfor table metadata loc | 1.002122 |
| rename result table | 0.000012 |
| Waitingfor table metadata loc | 1.001946 |
| rename result table | 0.000009 |
| Waitingfor table metadata loc | 1.001933 |
| rename result table | 0.000008 |
| Waitingfor table metadata loc | 1.001938 |
| rename result table | 0.000009 |
| Waitingfor table metadata loc | 1.001964 |
| rename result table | 0.000009 |
| Waitingfor table metadata loc | 0.586454 |
| rename result table | 0.003639 |
| end | 0.000019 |
| query end | 0.000135 |
| closing tables | 0.000018 |
| freeing items | 0.000019 |
| cleaning up | 0.000028 |
+--------------------------------+----------+
28 rows inset, 1 warning (0.00 sec)
果然”copy to tmp table”出现了,这次再MySQL 5.6.21版本的实验结果就跟之前在问题三的MySQL 5.5.28版本的实验结果是一致的了(上面profile的结果是一张1w行的小表,2000w的大表执行一次ddl等待时间太长了…)。