MySQL Online DDL:演变、原理与实践
在MySQL数据库的发展历程中,Online DDL功能的出现极大地提升了数据库表结构变更时的可用性和性能。从早期版本对表结构变更操作的诸多限制,到如今成熟的Online DDL体系,这一功能经历了显著的演进。
一、Online DDL的发展轨迹
MySQL在5.5版本中引入了INPLACE DDL方式,但由于实现上的缺陷,该方式依然会阻塞INSERT、UPDATE、DELETE等操作,给用户带来了极大的困扰。到了5.6版本,MySQL正式引入Online DDL功能,官方开始支持更多类型的ALTER TABLE操作以避免数据拷贝,并且在DDL过程中不再阻塞DML操作,真正实现了Online DDL。然而,并非所有的DDL操作都支持在线执行。
5.7版本在5.6的基础上进一步拓展,新增了重命名索引支持,同时支持数值类型长度的调整以及VARCHAR类型的在线增大。不过,其基本实现逻辑和限制条件与5.6版本相比并无根本性变化。
MySQL 8.0对DDL的实现进行了重新设计,最大的改进之一是支持DDL操作的原子特性。此外,Online DDL的ALGORITHM参数新增了INSTANT选项。该选项只需修改数据字典中的元数据,无需拷贝数据、重建表,也无需加排他MDL锁,整个DDL过程几乎瞬间完成,且不会阻塞DML操作。
二、Online DDL的算法剖析
在深入了解Online DDL之前,有必要先认识传统DDL的两种算法:copy和inplace。
Copy算法
Copy算法的执行步骤如下:首先按照原表定义创建一个新的临时表,接着对原表加写锁,禁止DML操作但允许select操作。随后在临时表上执行DDL,将原表数据拷贝到临时表,释放原表的写锁,最后删除原表,并将临时表重命名为原表。由于在操作过程中需要锁表,禁止DML,因此Copy算法不属于Online DDL。例如,删除主键、修改列类型、修改字符集等会导致行记录格式发生变化的操作,无法通过全量 + 增量实现Online,通常会采用Copy算法。
Inplace算法
Inplace算法直接在原表上进行更改,无需生成临时表和数据拷贝。根据是否变更行记录格式,Inplace算法又可分为两类:
- rebuild:需要重建表,重新组织聚簇索引。例如,optimize table、添加索引、添加/删除列、修改列NULL/NOT NULL属性等操作。对于这类操作,Online的实现方式是缓存DDL期间的DML,待DDL完成后,将DML应用到表上。
- no - rebuild:无需重建表,仅需修改表的元数据,如删除索引、修改列名、修改列默认值、修改列自增值等操作。
在Copy数据到新表期间,原表上加的是MDL读锁,允许DML操作,禁止DDL操作;在应用增量期间,对原表加MDL写锁,禁止DML和DDL操作。需要注意的是,根据表A重建出来的数据放在tmp_file里,这个临时文件由InnoDB在内部创建,整个DDL过程都在InnoDB内部完成。对于Server层来说,数据并未挪动到临时表,这就是“Inplace”名称的由来。
三、Online DDL过程中的锁机制
默认情况下,MySQL支持Online DDL操作,并且在执行过程中会尽量减少锁的使用,无需特殊操作即可启用。然而,MySQL在选择锁机制时,尽管会尽量减少限制,但仍有可能选择使用锁。为了避免因锁导致表无法读写的情况,可以在执行Online DDL语句时,使用ALGORITHM和LOCK关键字。
ALGORITHM的选项
- INPLACE:直接在原表上执行DDL操作。
- COPY:使用临时表方式,克隆临时表,在临时表上执行DDL,再导入数据并进行重命名。此过程需要额外一倍的磁盘空间,且执行期间表不允许DML操作。
- DEFAULT:默认方式,由MySQL自行选择,优先使用INPLACE方式。
LOCK的选项
- SHARE:共享锁,执行DDL的表可读取,但不可写入。
- NONE:无任何限制,执行DDL的表可读可写。
- EXCLUSIVE:排他锁,执行DDL的表不可读也不可写。
- DEFAULT:默认值,不指定LOCK子句时使用。不建议使用此选项,除非确定DDL语句不会锁表,否则应指定锁类型。
执行DDL操作时,ALGORITHM选项可以不指定,此时MySQL会按照INSTANT、INPLACE、COPY的顺序自动选择合适的模式。也可以指定ALGORITHM=DEFAULT,效果相同。若指定的ALGORITHM选项不被支持,会直接报错。
在执行Online DDL之前,应选择非业务高峰期,并确认待执行的表上没有未提交的事务、锁等信息。可通过特定SQL语句进行查看:
select * from information_schema.innodb_locks;
select * from information_schema.innodb_trx;
select * from information_schema.innodb_lock_waits;
select * from information_schema.processlist;
四、DDL操作的需求与挑战
DDL操作涉及数据库表结构的修改,如添加/删除列、修改列定义、添加/删除索引等。在早期版本中,执行这些操作时需要锁定整个表,严重影响数据库的可用性。因此,实现在线DDL成为提升系统灵活性和性能的关键需求。
五、MySQL 5.7在线DDL功能特点
MySQL 5.7通过InnoDB存储引擎对在线DDL功能进行了改进,主要特点如下:
- 支持添加辅助索引:可在运行中的表上添加辅助索引,无需锁定整个表。
- 支持修改列定义:能够在线修改列的数据类型、长度等定义。
- 支持修改字符集和排序规则:可在线修改表的字符集和排序规则设置。
- 支持重命名列:可在不影响读写操作的情况下,对表中的列进行重命名。
六、实现原理与优化
在线DDL功能的实现包含以下关键步骤和优化措施:
- 创建临时表:创建临时表存储DDL操作所需的新结构,确保旧表仍可进行读写操作。
- 数据复制和同步:逐步将旧表数据复制到临时表,并保持两者数据同步,保证数据完整性和一致性。
- 变更捕获和重放:利用日志和重做日志等机制,捕获DDL操作期间的数据变更,并重放到临时表中,确保操作完成后数据的一致性。
- 最终切换:DDL操作完成后,数据库引擎在适当的时机切换到临时表,使其成为新的表结构,并对新表进行后续读写操作。
七、使用限制与注意事项
尽管MySQL 5.7的在线DDL功能提供了近似在线的体验,但仍存在一些限制和注意事项:
- 并非所有DDL操作都支持在线执行:部分操作仍需锁定整个表。
- 资源占用问题:DDL操作期间可能占用大量系统资源,在高负载时应谨慎使用。
- 充分评估和测试:进行在线DDL操作前,需对操作进行充分评估和测试,确保数据的完整性和一致性。
八、各版本支持的详细情况
相关数据可参考MySQL官方文档:
- https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl-operations.html
- https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html
- https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html
九、DDL的执行模式
- INSTANT DDL:MySQL 8.0引入的新功能,当前支持范围较小,包括修改二级索引类型、新增列、修改列默认值、修改列ENUM值、重命名表等操作。
- ALGORITHM选择策略:
- 用户显式指定ALGORITHM时,使用指定选项。
- 用户未指定时,若操作支持INPLACE,则优先选择INPLACE,否则选择COPY。当前不支持INPLACE的操作主要有删除主键、修改列数据类型、修改表字符集等。
- Online DDL的界定:从DML操作的角度来看,若DDL操作不阻塞DML操作,则为Online DDL。当前非Online DDL操作相对较少,主要包括新增全文索引、新增空间索引、删除主键、修改列数据类型、指定表字符集、修改表字符集等。更多详细示例可参考官方文档。
十、常见问题探讨
Q1:Online DDL会不会锁表?
要回答这个问题,首先需明确“锁表”的含义。在InnoDB表中,影响DML操作的锁包括MDL锁、表锁、行锁和GAP锁。其中,MDL锁在Server层添加,其他三种在InnoDB层添加。所有操作都需先获取Server层的MDL锁,再获取InnoDB层所需的锁。
DDL的基本过程为:开始时获取对应表的MDL X锁,进行准备工作;然后将MDL X锁降级为MDL S锁,执行真正的DDL操作;最后将MDL S锁升级为MDL X锁,完成DDL操作并释放MDL锁。因此,在真正执行DDL操作期间,不会“锁表”。但如果在第一阶段无法获取MDL X锁,就可能导致“锁表”。例如,当一个会话执行慢查询时,另一个会话尝试进行DDL操作,可能无法获取MDL X锁,从而导致后续的查询和操作无法执行,此时可认为表被“锁表”。在MySQL 5.7/8.0中,可开启performance_schema,通过查询metadata_locks表获取MDL锁的信息;阿里云RDS 5.6版本新增了I_S.MDL_INFO表,用于提供MDL的查询。
综上所述,Online DDL并非绝对安全,不能随意执行,线上操作应在业务低峰期谨慎进行。
Q2:支持INPLACE算法的DDL一定是Online的吗?
从概念上讲,INPLACE和Online是两个不同维度的概念。COPY和INPLACE描述的是DDL内部的执行逻辑,COPY是在Server层的操作,INPLACE是在InnoDB层的操作。而用户更关注的Online与否,通常只与是否允许并发DML有关。基本结论是:COPY算法执行的DDL肯定不是Online的;INPLACE算法执行的DDL不一定是Online的。
Q3:INPLACE DDL需不需要额外的数据空间?
MySQL内部对于DDL的ALGORITHM主要有INPLACE和COPY两种选择(8.0新增的INSTANT使用范围较小)。COPY算法通过创建临时表并拷贝原表数据,显然需要额外的数据空间。对于支持INPLACE算法的DDL,同样需要额外的数据空间。这是因为INPLACE描述的是表,而非数据文件。只要不创建临时表,都属于INPLACE操作。实际上,许多INPLACE DDL操作会重建表(创建临时数据文件),如增加主键、重建主键、新增列(8.0支持INSTANT DDL的情况除外)、删除列、调整列顺序、删除列默认值、增加列默认值、修改表的ROW_FORMAT、OPTIMIZE表等,这些操作都需要额外的数据空间。