补充MySQL官网知识--解锁Online VARCHAR字段扩展与Index的关系

大家可以先看本文的结论【即 4. 总结】,如有兴趣再顺读。

1. Online DDL Support for Column Operations

| Operation | In Place | Rebuilds Table | Permits Concurrent DML | Only Modifies Metadata |
| Adding a column | Yes | Yes | Yes* | No |
| Dropping a column | Yes | Yes | Yes | No |
| Renaming a column | Yes | No | Yes* | Yes |
| Reordering columns | Yes | Yes | Yes | No |
| Setting a column default value | Yes | No | Yes | Yes |
| Changing the column data type | No | Yes | No | No |
| Extending VARCHAR column size | Yes | No | Yes | Yes |
| Dropping the column default value | Yes | No | Yes | Yes |
| Changing the auto-increment value | Yes | No | Yes | No* |
| Making a column NULL | Yes | Yes* | Yes | No |
| Making a column NOT NULL | Yes* | Yes* | Yes | No |

Modifying the definition of an ENUM or SET column Yes No Yes Yes

2. Extending VARCHAR column size

| Operation | In Place | Rebuilds Table | Permits Concurrent DML | Only Modifies Metadata |

Extending VARCHAR column size Yes No Yes Yes

修改的语法如下

复制代码
ALTER TABLE tbl_name CHANGE COLUMN c1 c1 VARCHAR(255), ALGORITHM=INPLACE, LOCK=NONE;

The number of length bytes required by a VARCHAR column must remain the same. For VARCHAR columns of 0 to 255 bytes in size, one length byte is required to encode the value. For VARCHAR columns of 256 bytes in size or more, two length bytes are required. As a result, in-place ALTER TABLE only supports increasing VARCHAR column size from 0 to 255 bytes, or from 256 bytes to a greater size. In-place ALTER TABLE does not support increasing the size of a VARCHAR column from less than 256 bytes to a size equal to or greater than 256 bytes. In this case, the number of required length bytes changes from 1 to 2, which is only supported by a table copy (ALGORITHM=COPY). For example, attempting to change VARCHAR column size for a single byte character set from VARCHAR(255) to VARCHAR(256) using in-place ALTER TABLE returns this error:

复制代码
ALTER TABLE tbl_name ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(256);
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change
column type INPLACE. Try ALGORITHM=COPY.

注意:The byte length of a VARCHAR column is dependant on the byte length of the character set.

Decreasing VARCHAR size using in-place ALTER TABLE is not supported. Decreasing VARCHAR size requires a table copy (ALGORITHM=COPY).

---摘自官网:https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html#online-ddl-column-operations

注意:在有关Extending VARCHAR column size的说明中 ,官网没有涉及字段Index的内容。很可惜。

3. 不一样的风景

3.1 场景

不知读者是否已遇到或者注意到,给表的字段扩展长度有时候很快,而有时候有需要消耗几分钟。排除掉官网提到的字段长度encode临界值的修改---字节256,还是解释不了为什么会执行那么久。

按照官网的说明,在相同的encode字节要求下(1--255;256及以上), 这个操作只是修改了元数据,不需要Rebuilds Table,应该瞬间完成(或者说3S内)。那么执行了几分钟,是不是很有些因素是官网没有提到的。

3.2 举例说明

|------------------|-------------------------------------------------------------|
| MySQL版本 | 5.7.21 |
| Server配置 | 8核24G;VSAN盘 |
| 表--qq_order_cust | 记录数:760W Data length:2.8G Index length:1.5G Table Size:4.3G |
| 修改的列 | 列1:product_name VARCHAR(64) 列1:per_type VARCHAR(16) |
| table collation | utf8mb4_general_ci |

SQL语句1

复制代码
ALTER TABLE qq_order_cust ALGORITHM=INPLACE, CHANGE COLUMN product_name product_name VARCHAR(128);

product_name列的长度由64调整到128, 这条语句执行了247S,4分钟。--这个情况是用官网知识解释不了的,不符合预期。

SQL语句2

复制代码
ALTER TABLE qq_order_cust ALGORITHM=INPLACE, CHANGE COLUMN per_type per_type VARCHAR(32);

per_type列的长度由16调整到32,这条语句 瞬间完成,不到1S。---符合预期

有同学可能会认为会不会数据已缓存到内存中了,所以SQL语句2执行快了很多。这个我们排除掉了。--我们执行了语句3--将product_name 由128调整到132--,还是执行240多秒,所以,语句2执行快很快和数据内存无关。

按照官网的知识,上面两个语句都是应该瞬间执行完成的。

这是怎么回事?难道是随机的?这以后怎么评估执行时间和影响呢?

3.3 灵光乍现

反复比较,盯着表创建语句看了N遍,忽然发现 耗时久的那个字段上有index,是两个独立的索引Index,即这个字段和其它不同的字段分别组合了Composite Index。

难道耗时久,和index有关。

抱着尝试的心态,我们决定试下。

因为是验证环境,保存语句,然后,我们直接将这两个有关 product_name 的index直接删除掉了。

再执行 SQL4

复制代码
ALTER TABLE qq_order_cust ALGORITHM=INPLACE, CHANGE COLUMN product_name product_name VARCHAR(132);

长度由128调整到132,这次瞬间完成了,不到1S。---符合预期

惊喜,那就再验证一次

SQL5

复制代码
ALTER TABLE qq_order_cust ALGORITHM=INPLACE, CHANGE COLUMN product_name product_name VARCHAR(156);

这是还是瞬间完成。---符合预期

基于以上的验证,可以得出以下结论

结论: 修改有索引的字段的长度,不会瞬间完成,不是Only Modifies Metadata 。这是官网上没提到的。

3.4 继续探究

实验尚未。刚才说了,在两个关联索引的条件下耗时247S,如果只有一个关联index,不会快些。【注意:所谓的关联index,是指和指定字段有关联,和要修改的字段有关联】

我们想到这一点,已经欣欣然了,忍不住继续测试下去。

先仅修复其中一个index。在此条件下执行SQL6

复制代码
ALTER TABLE qq_order_cust ALGORITHM=INPLACE, CHANGE COLUMN product_name product_name VARCHAR(186);

SQL耗时变成了131S。耗时是原来的一半左右。------符合预期,小小激动。

继续修复第二个关联index,执行SQL7

复制代码
ALTER TABLE qq_order_cust ALGORITHM=INPLACE, CHANGE COLUMN product_name product_name VARCHAR(258);

此时,SQL耗时变成了242S。

基于以上的验证,可以得出以下结论

结论:修改有索引的字段的长度,其耗时 和 这个字段上索引的个数正相关;索引越多,耗时越久。这是官网上没提到的。

4. 总结

  1. Extending VARCHAR column size,字段的字节长度(255-->256)是个临界值。注意是字节,如果选用的字符集是utf8mb4,VARCHAR字段对应的VARCHAR(63)-->VARCHAR(64)是临界值。这点官网上有提到。

2.修改有索引的字段的长度,不会瞬间完成,不是Only Modifies Metadata。这是官网上没提到的。

3.修改有索引的字段的长度,其耗时 和 这个字段上索引的个数正相关;索引越多,耗时越久。这是官网上没提到的。

4. 官网中 字段长度扩展不Rebuilds Table、Only Modifies Metadata,这儿应该有个特指--仅指的是聚簇索引(Clustered Index),不包含辅助index(也被称为二级索引或非聚簇索引)。因为案例中的4分钟,应该是在重整字段相关的辅助ndex,通过监控也可以看到4分钟内有大量的IO操作。这是官网上没提到的。

备注

1.此测试是在MySQL 5.7.21 版本下验证的,MySQL8.0 版本下是什么表现,尚未验证。

2.本次字段扩展实验用的是utf8mb4字符集下VARCHAR类型。

相关推荐
东山絮柳仔2 个月前
关于数据库服务器资源降配的效能分析
性能优化·mysql 管理
东山絮柳仔2 个月前
mysqldump 参数拾遗:在遗忘与铭记之间
mysql 管理
东山絮柳仔3 个月前
MySQL 慢日志统计分析利器---pt-query-digest
mysql 管理
东山絮柳仔3 年前
Ansible操作MySQL常用的几个模块
linux·mysql 管理