![50de5fa22051edea62ab9d706a35659d.png](https://i-blog.csdnimg.cn/blog_migrate/5075f0ee826ad3b561de618de08bd252.jpeg)
上一篇文章我们讲了【MySQL数据类型测试】枚举数据类型ENUM的DDL变更测试(第四节)接下来我们深入介绍集合类型SET,测试基于InnoDB存储引擎上,对MySQL数据库集合类型SET的字段进行DDL变更操作,还是老问题:是否需要重新创建表呢?对数据库的事务处理有何影响?对数据库的数据服务提供有何性能影响?
(一)系统环境
硬件:DELL R510 10块盘做的RAID5,上面跑了几十个虚拟机
操作系统:CentOS release 5.5 (Final)
MySQL数据库:5.5.15-log
InnoDB存储引擎:plugin-InnoDB 1.1.8
(二)测试数据准备
鉴于测试数据准备需要用到MySQL函数和MySQL存储过程,SQL代码段需要占据文章大量的篇幅,不利于读者阅读关于集合类型SET字段上的DDL变更测试,此部分内容单整理成一篇文章MySQL数据库之数据类型集合类型和枚举类型测试环境。
(三)集合类型SET字段DDL变更
a)去掉集合类型字段定义的默认值属性
root@localhost : mysqlops 03:01:38> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘xiamen’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’) NOT NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
小结:
MySQL数据库集合类型字段定义属性为制定了非NULL且有缺省的默认值,对其进行DDL变更,单独去掉缺省的默认值属性,不会出现锁表、重建表等操作,这符合MySQL数据库表DDL变更的特性。
b)去掉集合类型字段定义的NOT NULL 属性
root@localhost : mysqlops 03:04:48> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘xiamen’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’);
Query OK, 20017251 rows affected (2 min 4.40 sec)
Records: 20017251 Duplicates: 0 Warnings: 0
小结:
MySQL数据库表字段的非NULL属性,修改为默认NULL属性,则会导致锁表与表重建,对于MySQL数据库集合类型字段也同样存在此问题。
c)增加集合类型字段定义的默认值
root@localhost : mysqlops 03:07:04> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘xiamen’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’) NOT NULL DEFAULT ‘shanghai’;
Query OK, 20017251 rows affected (2 min 4.79 sec)
Records: 20017251 Duplicates: 0 Warnings: 0
小结:
MySQL数据库表字段属性为NULL,修改为非NULL且有指定的缺省默认值,集合类型字段的DDL变更,也会导致锁表、重新创建等。
d)修改集合类型字段定义的默认值属性
root@localhost : mysqlops 03:11:44> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘xiamen’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’) NOT NULL DEFAULT ‘beijing’;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
小结:
对MySQL数据库表集合类型字段属性为非NULL且有缺省的默认值,仅仅是修改集合类型字段缺省的默认,MySQL数据库不会出现锁表等情况。
e)修改集合类型字段定义的默认值,且新默认值不在集合列表中
root@localhost : mysqlops 03:12:42> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘xiamen’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’) NOT NULL DEFAULT ‘suzhou’;
ERROR 1067 (42000): Invalid default value for ‘Work_City’
小结:
修改MySQL数据库集合类型字段缺省的默认值,为集合类型字段值域列表中不存在的集合元素,MySQL数据库回报错,并且集合类型字段的DDL变更SQL语句执行失败。
f)修改集合类型字段定义,尾部追加集合元素
root@localhost : mysqlops 03:12:52> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘xiamen’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’,‘nanchang’) NOT NULL DEFAULT ‘xian’;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
小结:
修改MySQL数据库集合类型字段的值域列表,为值域列表增加集合元素,以值域列表尾部追加的方式,这类DDL变更,不会导致MySQL数据库出现锁表等情况。
g)修改集合类型字段定义,调整集合元素的顺序
root@localhost : mysqlops 02:57:42> SELECT * FROM mysqlops_set_enum WHERE Work_City=4 LIMIT 1;
±—±------------±----------+
| ID | Work_Option | Work_City |
±—±------------±----------+
| 44 | | hangzhou |
±—±------------±----------+
1 row in set (0.00 sec)
root@localhost : mysqlops 03:13:03> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘xiamen’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’,‘nanchang’) NOT NULL DEFAULT ‘xian’;
Query OK, 20017251 rows affected (2 min 20.34 sec)
Records: 20017251 Duplicates: 0 Warnings: 0
备注:
DDL变更调整了集合元素 ‘xiamen’ 在集合元素值域列表中的位置,由原来存储序号32,调整为新的存储序号4,而涉及对比的集合元素 ‘hangzhou’ 由存储序号4,调整为新的存储序号8。
root@localhost : mysqlops 03:14:10> SELECT * FROM mysqlops_set_enum WHERE Work_City=4 LIMIT 1;
±—±------------±----------+
| ID | Work_Option | Work_City |
±—±------------±----------+
| 12 | | xiamen |
±—±------------±----------+
1 row in set (0.00 sec)
root@localhost : mysqlops 03:15:05> SELECT * FROM mysqlops_set_enum WHERE ID=44;
±—±------------±----------+
| ID | Work_Option | Work_City |
±—±------------±----------+
| 44 | | hangzhou |
±—±------------±----------+
1 row in set (0.00 sec)
root@localhost : mysqlops 03:16:14> SELECT * FROM mysqlops_set_enum WHERE ID=44 and Work_City=4;
Empty set (0.00 sec)
root@localhost : mysqlops 03:17:18> SELECT * FROM mysqlops_set_enum WHERE ID=44 and Work_City=8;
±—±------------±----------+
| ID | Work_Option | Work_City |
±—±------------±----------+
| 44 | | hangzhou |
±—±------------±----------+
1 row in set (0.00 sec)
root@localhost : mysqlops 03:18:28> SELECT * FROM mysqlops_set_enum WHERE Work_City=1 LIMIT 1;
±—±------------±----------+
| ID | Work_Option | Work_City |
±—±------------±----------+
| 1 | | shanghai |
±—±------------±----------+
1 row in set (0.00 sec)
小结:
我们事先随机显示了一条集合元素等于“hangzhou”的记录,自增序列唯一主键值为:44,方便我们对比MySQL数据库集合类型字段DDL变更之后的数据变化,总结如下:
MySQL数据库集合类型字段的定义属性的集合元素顺序调整,会导致MySQL数据库申请表级锁,并且锁表、创建临时文件等操作;
被DDL变更调整顺序的集合元素,其在MySQL数据库集合类型字段属性存储序号发生变化;
MySQL数据库集合类型字段的定义属性的集合元素顺序调整,导致受其影响的集合元素,字段定义属性中存储顺序都发生变化,数据库表对应的记录值的存储序号也发生变化;
MySQL数据库集合类型字段的定义属性的某个集合元素顺序调整,对其他存储序号未改变的集合元素,对其对应表字段存储的数据序号编号也未发生变化;
h)修改集合类型字段定义,删除某个集合元素
root@localhost : mysqlops 02:07:28> SELECT COUNT() FROM mysqlops_set_enum WHERE Work_city=’’;
±---------+
| COUNT() |
±---------+
| 200559 |
±---------+
root@localhost : mysqlops 02:20:39> SELECT COUNT() FROM mysqlops_set_enum WHERE Work_City=‘shenzhen’;
±---------+
| COUNT() |
±---------+
| 600160 |
±---------+
1 row in set (7.82 sec)
root@localhost : mysqlops 02:25:00> SELECT * FROM mysqlops_set_enum WHERE Work_city=‘shenzhen’ limit 1;
±----±------------±----------+
| ID | Work_Option | Work_City |
±----±------------±----------+
| 117 | | shenzhen |
±----±------------±----------+
1 row in set (0.00 sec)
root@localhost : mysqlops 03:16:05> ALTER TABLE mysqlops_set_enum MODIFY Work_City SET(‘shanghai’,‘beijing’,‘xiamen’,‘hangzhou’,‘guangzhou’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’,‘nanchang’) NOT NULL DEFAULT ‘xian’;
Query OK, 20017251 rows affected, 65535 warnings (2 min 22.09 sec)
Records: 20017251 Duplicates: 0 Warnings: 3801649
root@localhost : mysqlops 03:18:48> SHOW WARNINGS;
±--------±-----±-------------------------------------------------+
| Level | Code | Message |
±--------±-----±-------------------------------------------------+
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 11 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 19 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 34 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 41 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 47 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 50 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 62 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 69 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 76 |
| Warning | 1265 | Data truncated for column ‘Work_City’ at row 82 |
root@localhost : mysqlops 03:19:14> SELECT COUNT() FROM mysqlops_set_enum WHERE Work_city=’’;
±---------+
| COUNT() |
±---------+
| 800719 |
±---------+
1 row in set (6.29 sec)
root@localhost : mysqlops 03:24:09> SELECT * FROM mysqlops_set_enum WHERE ID=117;
±----±------------±----------+
| ID | Work_Option | Work_City |
±----±------------±----------+
| 117 | | |
±----±------------±----------+
1 row in set (0.00 sec)
小结:
DDL变更SQL语句删除MySQL数据库集合类型字段定义属性的某个集合元素,且该集合元素有对应的数据行存储于数据库表中,将会导致:
MySQL数据库表需要表级别锁,进行锁住表、重建表等操作;
被删除集合元素,对应的数据库表记得行字段的值,将会出现截断,以空字符串替代;
被删除集合元素之后的集合元素存储序号发生变化;
数据库表中集合类型字段的数据值,为保证对应集合类型字段定义属性中的集合元素存储序号,也会做相应的调整;
(四)基于集合类型SET字段的索引
a)完成DDL变更之后的数据库表结构
root@localhost : mysqlops 03:25:42> SHOW CREATE TABLE mysqlops_set_enumG
*************************** 1. row ***************************
Table: mysqlops_set_enum
Create Table: CREATE TABLE mysqlops_set_enum (
ID int(11) NOT NULL AUTO_INCREMENT,
Work_Option enum(‘JavaScript’,‘DBA’,‘SA’,‘C++’,‘NA’,‘QA’,‘Java’,‘other’,’’,‘Python’) NOT NULL DEFAULT ‘DBA’,
Work_City set(‘shanghai’,‘beijing’,‘xiamen’,‘hangzhou’,‘guangzhou’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’,‘nanchang’) NOT NULL DEFAULT ‘xian’,
PRIMARY KEY (ID)
) ENGINE=InnoDB AUTO_INCREMENT=20017252 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
b)MySQL数据库集合类型字段无创建索引时,SQL语句执行计划
root@localhost : mysqlops 03:34:59> EXPLAIN SELECT * FROM mysqlops_set_enum WHERE Work_City=8 LIMIT 1G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: mysqlops_set_enum
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 20017710
Extra: Using where
1 row in set (0.00 sec)
小结:
MySQL数据库表集合类型字段没有创建索引时,集合类型字段作为数据查找条件,完全符合MySQL数据库使用索引的规则,依然是全表扫描,说明集合类型字段定义属性的内部存储序列编号,不能起到数据库索引的功效。
c)MySQL数据库集合类型字段创建索引
root@localhost : mysqlops 03:35:44> ALTER TABLE mysqlops_set_enum ADD INDEX idx_work_city_set(Work_City);
Query OK, 0 rows affected (1 min 32.40 sec)
Records: 0 Duplicates: 0 Warnings: 0
小结:
为MySQL数据库表集合类型字段创建索引,与文章MySQL 5.5版本对普通索引增删性能的优化描述一样,需要锁表、重新创建表等操作,集合类型字段创建索引也同样需要这样做。
d)MySQL数据库集合类型字段有索引时,SQL语句执行计划
root@localhost : mysqlops 03:38:04> EXPLAIN SELECT * FROM mysqlops_set_enum WHERE Work_City=8 LIMIT 1G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: mysqlops_set_enum
type: ref
possible_keys: idx_work_city_set
key: idx_work_city_set
key_len: 2
ref: const
rows: 2024666
Extra: Using where
1 row in set (0.00 sec)
小结:
MySQL数据库表集合类型字段创建数据库索引之后,同样的数据查找SQL语句,则会根据索引条件查找数据,而不是全表扫描。
e)MySQL数据库集合类型字段上的索引删除
root@localhost : mysqlops 03:44:59> ALTER TABLE mysqlops_set_enum DROP INDEX idx_work_city_set;
Query OK, 0 rows affected (0.82 sec)
Records: 0 Duplicates: 0 Warnings: 0
小结:
MySQL数据库表集合类型字段上的索引删除DDL变更,同样会导致MySQL数据库使用表级锁,锁表、重新创建表等一系列操作。
(五)总结
对MySQL数据库集合类型的字段定义属性,进行了定义属性默认值去除、NOT NULL 修改为NULL 、默认为NULL修改为NOT NULL和缺省默认值、修改缺省的默认值、尾部追加新的集合元素、调整集合元素的位置、为集合元素字段创建索引、观察数据查找SQL语句执行计划、删除索引等一系列的DDL操作,以及观察数据库表中的集合数据变化,我们得出下列结论:
a)集合类型字段的DDL变更,对MySQL数据库的影响基本上与其他数据类型字段的DDL变更类似;
b)集合类型字段的集合元素顺序调整,会导致受影响的集合元素存储编号调整,对应的数据库表中的数据编号也会被修改;
c)集合类型字段的集合元素顺序调整,不会跟枚举类型字段一样,出现数据库表数据对照关系的紊乱;
d)集合类型字段的集合元素与表存储的顺序编号之间的对照关系,无法起到索引查找数据的功能。需要时,推荐为数据库表集合类型字段创建索引;
e)鉴于集合类型字段的集合元素顺序调整,会导致数据库表锁住等操作,建议不要轻易调整集合元素的顺序;
f)集合类型字段的集合元素增加,最好尾部追加的方式增加,否则需要锁表等一系列操作,影响数据库表的事务处理;
g)删除集合类型字段定义的某个集合元素,会导致数据库表中对应的数据行发生截断行为,并且用空字符串替代;
h)集合类型字符定义属性,最好申明为NOT NULL,且有缺省的默认值数据。
如果这篇文章有帮助到你,可以点进我的主页查看往期系列文章。
我们明天见啦~
![b637a2908e58aaae56f7499e2e7797a7.png](https://i-blog.csdnimg.cn/blog_migrate/9293adb099c26a2d56d59099bdec59d3.jpeg)
---------------------
作者:Amy—go