引言

众所周知,在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) 不支持
修改索引类型 不需要
  1. 在添加表上第一个全文索引时,如果没有用户定义的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列的定义 不需要
  1. 秒级加列仅支持添加列到表的末尾,并且表需要已有主键(否则可能会因为最末尾的隐式主键导致Instant Add Column失败)。另外,Instant Add Column不支持压缩表(ROW_FORMAT=COMPRESSED),不支持全文索引的表,不支持临时表。如果不支持Instant Add Column,增加列默认走INPLACE DDL,需要全表重建。此时支持通过并行DDL加速,允许并发DML。
  2. 扩展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。此时,如果不支持快速列扩展,会直接报错。如下给出了一个参考示例:
  1. ALTER TABLE table_name ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(256);
  2. ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change
  3. 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 支持
重建表 支持
重命名表 不需要
  1. 如果新的character发生变化,需要走COPY DDL重建表的方式
  2. 通过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 不需要
  1. 由于增加Stored Column表达式涉及SQL/Server层,因此不支持Online DDL。

Foreign Key操作

操作 允许并发DML 重建表 秒级完成 支持并行DDL
增加Foregin Key 是1 否1 是1 不需要
删除Foregin Key 是1 否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) 不支持
分区转表 不支持
  1. 支持分区级元数据锁,开启loose_partition_level_mdl_enabled参数后,DDL不影响不涉及的分区上的DML。
  2. 只有RANGE/LIST分区支持。
  3. 只支持QUERY。

总结

由于篇幅原因,本文仅介绍了部分常见的DDL操作,希望能够帮助用户在执行DDL前,了解相关DDL在云原生数据库PolarDB MySQL 8.0.2版本上的行为特征。总的来说,经过多年的持续优化,借助于并行DDL、Instant DDL、DDL IO优化等方面的工作,PolarDB MySQL在DDL方面已经形成了较大的优势。未来,PolarDB内核团队将继续在DDL方面发力,进一步提升DDL的易用性,始终如一地为用户打造最佳的云原生数据库。