当前位置: 首页 > 科技观察

MySQLOnlineDDL,还是要慎重

时间:2023-03-15 16:10:30 科技观察

指南阅读MySQL的OnlineDDL被诟病已久。8.0以后是不是更好了……本文主要介绍几种常见的OnlineDDL需求:添加新列(ADDCOLUMN)修改列定义(MODIFYCOLUMN)添加/删除索引(ADD/DROPINDEX)其他DDL相对较少操作,所以本文将不讨论它。另外,本文不讨论非InnoDB引擎和非常用索引(如全文索引、空间索引)的场景。我们先看看ALGORITHM在ALTERTABLE时可以指定的几种方式:COPY是指在DDL时,会生成一个(临时的)新表,将原表数据逐行复制到新表中。在此期间,DMLINPLACE将被阻塞。不需要将整张表数据复制到新表中,但是可能还是需要用IN-PLACE方法(就地,不生成新的临时表)来重建整张表。在这种情况下,通常需要在DDL的初始准备和最终结束时加一个独占MDL锁(metadatalock,元数据锁)。另外DMLINSTANT在DDL时不会阻塞,只需要修改数据字典即可。对于元数据,无需复制数据或重建整个表。同样不需要加排他MDL锁,原表数据不受影响。整个DDL过程几乎是瞬时的,不会阻塞DML。这个新功能是在8.0.12中引入的。再次感谢腾讯互娱DBA团队的贡献。执行DDL操作时,可以不指定ALGORITHM选项。这时MySQL会自动按照INSTANT、INPLACE、COPY的顺序选择合适的模式。您还可以指定ALGORITHM=DEFAULT,这具有相同的效果。如果指定了ALGORITHM选项但不支持,会直接报错。当使用COPY方式时,此时对表进行任何数据修改操作,DDL都会被阻塞。在COPY模式下,会生成一个临时的新表。操作完成后,原表将被删除,新表将重命名为原表名。当DDL启动时,原表只能是只读的,其他DML操作也会被阻塞。在COPY过程中,唯一阻塞只读的时间是在清理旧表结构和表定义缓存时。1、下面是支持INPLACE模式的几种情况:InnoDB表本身支持的在线DDL操作表重命名。以下操作只修改表元数据,不修改表数据。字段类型为CHAR、VARCHAR、TEXT、ENUM字符将集合从UTF8MB3改为UTF8MB4,或者从任何其他字符集改为二进制将字符集的字段更改为字段上没有索引重命名字段以修改默认值index重命名添加或删除辅助索引更改索引的可见性ENUM/SETtypefield添加一个新值,例如在('a','b')之后添加'c'变为('a','b','c')从8.0.14开始,以下情况只修改字符集从8.0.14开始,虚拟列(生成列)上的定义类型、表达式、是否允许NULL约束不做修改)InnoDB表。比如只修改字段remarks的内容(这个很有用)修改字段的默认值,并且该字段不包含在生成虚拟列的表达式中,比如只修改字段的NULL属性2、以下是支持INSTANT模式的几种情况:在表的末尾添加新字段添加或删除虚拟列添加或删除删除字段的默认值,修改ENUM/SET字段定义。上面也提到了修改索引类型,重命名表。运行过程中,5.5版本之前的时间类型相关字段会强制升级到更高版本。本次升级需要重建整个表,只能使用COPY方式。这时候如果指定ALGORITHM=INPLACE,就会报错。当有联合索引用于表分区时,如果修改联合索引列的顺序,也需要COPY方式。4.最后用一张表格来说明几种常见的操作模式。OperationInstantInPlace可以并行重建表。DML只是修改元数据和添加辅助索引。是否删除辅助索引。否是是是否删除主键否否是否同时删除和添加主键否是是是否添加字段是(追加)是否删除字段否是是修改字段数据类型NoNoYesNo延长VARCHAR列长度NoYesYes添加STORED虚拟列NoNoYesNo添加VIRTUAL虚拟列YesYesYes转换表字符集NoNoYesNoOpitmizetableNoYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYes是的是的是的是的是的是的是的是的是的是的是的是的名字是的,最后有两个提示。一般DDL操作最好用pt-osc或gh-ost等工具实现,并且在实现之前需要检查当前目标表是否有事务或大查询。避免严重等待MDL锁。除了8.0以上的版本,除了追加新列、表重命名、添加虚拟列这三个支持INSTANT的操作可以直接运行DDL,其他操作都使用pt-osc/gh-osc工具,它相对不太容易执行ALTERTABLEDDL,不指定ALGORITHM=?,LOCK=?options,因为MySQL会判断使用哪种方法本来可以是INPLACE,但是一不小心指定为COPY就悲剧了