每一个你不满意的现在,都有一个你不努力的曾经。

MySQL Online DDL


测试表结构

CREATE TABLE `t3` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `dept` tinyint(4) NOT NULL COMMENT '部门id',
  `name` varchar(30) DEFAULT NULL COMMENT '用户名称',
  `create_time` datetime NOT NULL COMMENT '注册时间',
  `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
  PRIMARY KEY (`id`) USING BTREE,
) ENGINE=InnoDB AUTO_INCREMENT=2097165 DEFAULT CHARSET=utf8mb4 COMMENT='测试表';

开两个 session

创建全文索引时,仅支持读,会阻塞写

mysql-1>alter table t3 add fulltext index idx_1(name);
#执行中.......

mysql-2>insert into t3 values(2097164,4,'user_2097164',now(),now());
#等待中.......

optimize table或者alter table ... engine=innodb,不会阻塞写

mysql-1> alter table t3 engine=innodb;
#执行中.......
Query OK, 0 rows affected (9.28 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql-2> insert into t3 values(2097166,6,'user_2097166',now(),now());
Query OK, 1 row affected (0.01 sec)

optimize table或者alter table ... engine=innodb 存在全文索引时,会阻塞写

mysql-1>alter table t3 add fulltext index idx_1(name);

mysql-1> alter table t3 engine=innodb;
#执行中.......
Query OK, 2097165 rows affected (28.14 sec)     # 有数据受到影响
Records: 2097165  Duplicates: 0  Warnings: 0

# 有数据受到影响 查看
mysql-1> show profile;
+----------------------+-----------+
| Status               | Duration  |
+----------------------+-----------+
| starting             | 0.000047  |
| checking permissions | 0.000005  |
| checking permissions | 0.000003  |
| init                 | 0.000004  |
| Opening tables       | 0.000272  |
| setup                | 0.000030  |
| creating table       | 0.003757  |
| After create         | 0.000138  |
| System lock          | 0.056069  |
| copy to tmp table    | 27.775030 |  #copy to tmp table
| rename result table  | 0.302859  |
| end                  | 0.000010  |
| query end            | 0.000003  |
| closing tables       | 0.000010  |
| freeing items        | 0.000059  |
| cleaning up          | 0.000006  |
+----------------------+-----------+
16 rows in set (0.07 sec)
# 说明有全文索引时 optimize table 或者 alter table 进行了 copy tablecopy table

# 执行 alter table 同时 执行插入,会阻塞写
mysql-2> insert into t3 values(2097167,7,'user_2097167',now(),now());
#等待中.......
Query OK, 1 row affected (27.50 sec)

添加列 表结构

CREATE TABLE `t3` (
  `id` int(11) NOT NULL COMMENT '',
  `dept` tinyint(4) NOT NULL COMMENT '部门id',
  `name` varchar(30) DEFAULT NULL COMMENT '用户名称',
  `create_time` datetime NOT NULL COMMENT '注册时间',
  `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
) ENGINE=InnoDB AUTO_INCREMENT=2097165 DEFAULT CHARSET=utf8mb4 COMMENT='测试表';

用例1:添加 auto_increment 列要锁表,会阻塞写

mysql-1> alter table t3 add column tid int not null primary key auto_increment;
#执行中.......
Query OK, 0 rows affected (14.26 sec)
Records: 0  Duplicates: 0  Warnings: 1

mysql> insert into t3 values(2097168,8,'user_2097168',now(),now(),2097168);
#等待中.......
Query OK, 1 row affected (13.58 sec)

用例2:添加普通列是 online 的,不会阻塞写

mysql> alter table t3 add column content1 text;
#执行中.......
Query OK, 0 rows affected (8.78 sec)
Records: 0  Duplicates: 0  Warnings: 0  

mysql-2> insert into t3 values(2097170,7,'user_2097170',now(),now());
Query OK, 1 row affected (0.00 sec)

用例3:修改列类型,会阻塞写

mysql-1> alter table t3 change content1 content1 longtext;  
#执行中.......
Query OK, 2097169 rows affected (9.99 sec)      #有受影响行数
Records: 2097169  Duplicates: 0  Warnings: 0

mysql-2> insert into t3 values(2097171,1,'user_2097171',now(),now(),'a');
#等待中.......
Query OK, 1 row affected (9.50 sec)

# 有数据受到影响 查看
mysql-1> show profile;
+----------------------+-----------+
| Status               | Duration  |
+----------------------+-----------+
| starting             | 0.000107  |
| checking permissions | 0.000006  |
| checking permissions | 0.000006  |
| init                 | 0.000013  |
| Opening tables       | 0.000330  |
| setup                | 0.000058  |
| creating table       | 0.004067  |
| After create         | 0.000233  |
| System lock          | 0.011582  |
| copy to tmp table    | 10.594625 |    #copy to tmp table
| rename result table  | 0.019796  |
| end                  | 0.000010  |
| query end            | 0.000004  |
| closing tables       | 0.000009  |
| freeing items        | 0.000049  |
| cleaning up          | 0.000037  |
+----------------------+-----------+
16 rows in set (0.07 sec)

#注:修改列类型 DDL 采用 copy table 方式并且阻塞写入,线上操作须谨慎

常用DDL执行方式总结

<怕>

操作 支持方式 Allow R/W 说明
add/create index online 允许读写 当表上有FULLTEXT索引除外,需要锁表,阻塞写
add fulltext index in-place(5.6以上版本) 仅支持读,阻塞写

创建表上第一个fulltext index用copy table方式,除非表上 FTS_DOC_ID列。

之后创建fulltext index用in-place方式,经过测试验证,第一次时5.6 innodb

会隐含自动添加FTS_DOC_ID列,也就是5.6都是in-place方式

drop index online 允许读写 操作元数据,不涉及表数据。所以很快,可以放心操作
optimize table online 允许读写

当带有fulltext index的表用copy table方式并且阻塞写

alter table...engine=innodb online 允许读写

当带有fulltext index的表用copy table方式并且阻塞写

add column online 允许读写,(增加自增列除外)

1、添加auto_increment列或者修改当前列为自增列都要锁表,阻塞写;2、虽采用online方式,但是表数据需要重新组织,所以增加列依然是昂贵的操作,小伙伴尤其注意啦

drop column online  允许读写(增加自增列除外) 同add column,重新组织表数据,,昂贵的操作
Rename a column online 允许读写 操作元数据;不能改列的类型,否则就锁表(已验证)
Reorder columns online 允许读写 重新组织表数据,昂贵的操作
Make column NOT NULL online 允许读写 重新组织表数据,昂贵的操作
Change data type of column copy table 仅支持读,阻塞写 创建临时表,复制表数据,昂贵的操作(已验证)
Set default value for a column online 允许读写

操作元数据,因为default value存储在frm文件中,不涉及表数据。所以很快,

可以放心操作

alter table xxx auto_increment=xx online 允许读写 操作元数据,不涉及表数据。所以很快,可以放心操作
Add primary key online 允许读写 昂贵的操作(已验证)
Convert character set copy table 仅支持读,阻塞写 如果新字符集不同,需要重建表,昂贵的操作

参考:https://blog.csdn.net/huiyunfei/article/details/120483509

Card image cap

每一个你不满意的现在,都有一个你不努力的曾经。