引言
众所周知,在MySQL生态下,DDL是一类非常复杂的操作,涵盖了Index变更、Primary Key变更、Column列结构变更、Table表结构变更、Foreign Key操作、Generated Column列结构变更等多种不同类型的操作。DDL不仅持续时间久、消耗硬件资源多,而且其中涉及的锁表操作更成为了很多用户的梦魇,操作不慎就可能导致影响正常业务,造成灾难性的影响。
云原生数据库PolarDB MySQL在DDL方面经过多年的经验积累和持续的功能迭代,目前在性能和锁稳定性方面取得了长足的进步。本文将基于PolarDB MySQL 8.0.2版本,介绍不同类型DDL的执行方式,供用户查询了解,以期帮助用户了解DDL的行为,评估DDL操作风险,降低对业务的影响。对于DDL操作,本文主要从如下几个方面展开介绍。
- 是否锁表(允许并发DML):非锁表的DDL(Online DDL)只在修改元数据步骤申请表互斥锁(持续时间一般不超过1秒),在表结构变更期间允许对目标表进行读写操作,提高了在生产环境中的响应速度和可用性。相反,非Online方式执行的 DDL 会全程锁表,不支持并发的写入操作,当DDL操作持续较长时间时,可能会对业务操作造成重大影响。
- 是否重建表(持续时间长短):这类DDL,需要根据新的表结构,需要重新创建Primary Key以及所有二级索引,通常需要花费较长时间。值得注意的是,即使重建表,PolarDB内核的DDL性能也远优于gh-ost/pt-osc等第三方工具;
- 是否只修改元数据(秒级完成):只修改元数据的操作,不修改表数据,即DDL不会随着表规模变大而影响性能,一般秒级即可完成
- 是否支持并行DDL(多线程加速):对于大表创建索引/重建表等场景,PolarDB支持通过并行DDL,多线程加速DDL的完成,最高有15-20倍的性能提升。
Index操作
操作 |
允许并发DML |
重建表 |
秒级完成 |
支持并行DDL |
创建二级索引 |
是 |
否 |
否 |
支持 |
删除二级索引 |
是 |
否 |
是 |
不需要 |
重命名二级索引 |
是 |
否 |
是 |
不需要 |
增加全文索引 (FULLTEXT) |
否 |
否1 |
否 |
不支持 |
增加空间索引 (SPATIAL) |
否 |
否 |
否 |
不支持 |
修改索引类型 |
是 |
否 |
是 |
不需要 |
- 在添加表上第一个全文索引时,如果没有用户定义的FTS_DOC_ID列,会导致额外的重建表操作。
Primary Key操作
操作 |
允许并发DML |
重建表 |
秒级完成 |
支持并行DDL |
增加Primary Key |
是 |
是 |
否 |
支持 |
删除Primary Key |
否 |
是 |
否 |
不支持 |
删除原来Primary Key, 增加新的Primary Key |
是 |
是 |
否 |
支持 |
Column操作
操作 |
允许并发DML |
重建表 |
秒级完成 |
支持并行DDL |
增加列 |
是 |
否1 |
是1 |
支持1 |
删除列 |
是 |
是 |
否 |
支持 |
重命名列 |
是 |
否 |
是 |
不需要 |
重排序列 |
是 |
是 |
否 |
支持 |
设置列的默认值 |
是 |
否 |
是 |
不需要 |
修改列类型 |
否 |
是 |
否 |
不支持 |
扩展VARCHAR长度 |
是2 |
否 |
是 |
不需要 |
删除列默认值 |
是 |
否 |
是 |
不需要 |
修改auto-increment值 |
是 |
否 |
否 |
不需要 |
变更某列为NULL |
是 |
是 |
否 |
支持 |
变更某列为非NULL |
是 |
是 |
否 |
支持 |
修改ENUM/SET列的定义 |
是 |
否 |
是 |
不需要 |
- 秒级加列仅支持添加列到表的末尾,并且表需要已有主键(否则可能会因为最末尾的隐式主键导致Instant Add Column失败)。另外,Instant Add Column不支持压缩表(ROW_FORMAT=COMPRESSED),不支持全文索引的表,不支持临时表。如果不支持Instant Add Column,增加列默认走INPLACE DDL,需要全表重建。此时支持通过并行DDL加速,允许并发DML。
- 扩展VARCHAR长度:存储VARCHAR列长度所需的字节数需要保持一致,才能支持快速修改。具体来说,对于0-255Bytes的VARCHAR列,只需要一个Byte存储长度。而对于大于等于256Bytes的VARCHAR列,就需要两个Bytes存储长度。只有控制VARCHAR列长度的扩展范围,比如从0-255Bytes,或者从256Bytes到更大的范围,才能支持ALTER TABLE只修改元数据。也就是说,当修改VARCHAR列长度从小于256Bytes到大于256Bytes的长度时,PolarDB默认走Copy DDL类型,即全程都是锁表的,不支持DML写操作,仅支持读操作。当用户不确定自己修改VARCHAR列的范围是否满足上述条件时,可以手动执行DDL的执行方式为INPLACE。此时,如果不支持快速列扩展,会直接报错。如下给出了一个参考示例:
ALTER TABLE table_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.
varchar类型属于变长存储类型,磁盘仅存储实际长度,因此建议用户在使用varchar字段时,考虑将最大长度直接调整到256以上,避免扩展字段时可能需要走copy算法。
Table操作
操作 |
允许并发DML |
重建表 |
秒级完成 |
支持并行DDL |
修改ROW_FORMAT |
是 |
是 |
否 |
支持 |
修改KEY_BLOCK_SIZE |
是 |
是 |
否 |
支持 |
设置持久化统计信息 |
是 |
否 |
是 |
不需要 |
声明character set |
是 |
是1 |
否 |
支持 |
转换character set |
否 |
是 |
否 |
不支持 |
Optimize表 |
是 |
是2 |
否 |
支持 |
重建表 |
是 |
是 |
否 |
支持 |
重命名表 |
是 |
否 |
是 |
不需要 |
- 如果新的character发生变化,需要走COPY DDL重建表的方式
- 通过ALTER TABLE table_name ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE,重新整理表中的碎片时,带全文索引的表不支持INPLACE。
Generated Column操作
操作 |
允许并发DML |
重建表 |
秒级完成 |
支持并行DDL |
增加STORED Column |
否1 |
是 |
否 |
不支持 |
修改STORED Column顺序 |
否 |
是 |
否 |
不支持 |
删除STORED Column |
是 |
是 |
否 |
支持 |
增加VIRTUAL Column |
是 |
否 |
是 |
不需要 |
修改VIRTUAL Column顺序 |
否 |
是 |
否 |
不支持 |
删除VIRTUAL Column |
是 |
否 |
是 |
不需要 |
- 由于增加Stored Column表达式涉及SQL/Server层,因此不支持Online DDL。
Foreign Key操作
操作 |
允许并发DML |
重建表 |
秒级完成 |
支持并行DDL |
增加Foregin Key |
是1 |
否1 |
是1 |
不需要 |
删除Foregin Key |
是1 |
否1 |
是1 |
不需要 |
- 只有关闭了foreign_key_checks开关情况下,才支持INPLACE DDL,并且只修改元数据。否则只支持COPY DDL,全程锁表。
分区表操作
操作 |
允许并发DML |
秒级完成 |
In Place |
支持并行DDL |
表转分区 |
否 |
否 |
否 |
不支持 |
增加分区(ADD) |
是1 |
否 |
是2 |
不支持 |
删除分区(DROP) |
是1 |
否 |
是2 |
不支持 |
删除分区表空间(DISCARD) |
否 |
否 |
否 |
不支持 |
导入分区表空间(IMPORT) |
否 |
否 |
否 |
不支持 |
截断分区(TRUNCATE) |
是 |
否 |
是 |
不支持 |
合并分区(HASH/KEY分区) |
否 |
否 |
是3 |
不支持 |
重分布分区(REORGNIZATE |
否1 |
否 |
是3 |
不支持 |
交换分区(EXCHANGE) |
是1 |
否 |
是 |
不支持 |
分析分区(ANALYZE) |
是 |
否 |
是 |
不支持 |
检查分区(CHECK) |
是 |
否 |
是 |
不支持 |
优化分区(OPTIMIZE) |
否 |
否 |
否 |
不支持 |
重建分区(REBUILD) |
否1 |
否 |
是3 |
不支持 |
修复分区(REPAIR) |
是 |
否 |
是 |
不支持 |
分区转表 |
否 |
否 |
否 |
不支持 |
- 支持分区级元数据锁,开启loose_partition_level_mdl_enabled参数后,DDL不影响不涉及的分区上的DML。
- 只有RANGE/LIST分区支持。
- 只支持QUERY。
总结
由于篇幅原因,本文仅介绍了部分常见的DDL操作,希望能够帮助用户在执行DDL前,了解相关DDL在云原生数据库PolarDB MySQL 8.0.2版本上的行为特征。总的来说,经过多年的持续优化,借助于并行DDL、Instant DDL、DDL IO优化等方面的工作,PolarDB MySQL在DDL方面已经形成了较大的优势。未来,PolarDB内核团队将继续在DDL方面发力,进一步提升DDL的易用性,始终如一地为用户打造最佳的云原生数据库。