更新时间:2024-03-14 GMT+08:00

instant秒级加列

背景

通常情况下大表的DDL操作都会对业务产生很大的影响,需要在业务低峰期做。MySQL 5.7支持Online DDL已经一些在线工具gh-ost等,减少了DDL期间DML操作被阻塞的情况。但是大表DDL仍然需要花费很长时间。

instant秒级加列算法,让添加列的时候不在需要rebuild整个表,只需要在表的metadata中记录新增列的基本信息即可,可以很快执行完成。但是目前支持的DDL操作有限。

语法

在Alter语句后面增加“ALGORITHM=INSTANT”即代表使用instant算法,例如:

ALTER TABLE *tbl_name* ADD COLUMN *column_name* *column_definition*, ALGORITHM=INSTANT;

使用限制

使用场景的限制:

  • 部分场景下增加、删除、重命名(MySQL 8.0.28之后)列。
  • 设置或删除列的默认值。
  • 修改ENUM或SET列的定义。
  • 更改索引的类型(BTREE | HASH)。
  • 增加或删除虚拟列。
  • 表名重命名。

添加或删除列的限制:

  • 不支持有其他INSTANT语句在同一行的操作在同一条语句的情况。
  • 新增列将会放到最后,不支持改变列的顺序(MySQL 8.0.29后支持任意位置加列)。
  • 不支持在行格式为COMPRESSED的表上快速加列或删除。
  • 不支持在已经有全文索引的表上快速加列或删除。
  • 不支持在临时表上快速加列或删除。

重命名列的限制:

  • 不支持重命名被其他表引用的列。
  • 不支持重命名列的操作与生成或者删除虚拟列在同一个语句中。

修改ENUM或SET列的限制:

  • 不支持ENUM或者SET列数据类型占用的存储空间发生变化。

增加或删除虚拟列的限制:

  • 不支持对分区表的增加或删除操作。

新的数据字典信息

在执行instant add column的过程中,MySQL会将第一次intant add column之前的字段个数以及每次加的列的默认值保存在tables系统表的“se_private_data”字段中。

  • dd::Table::se_private_data::instant_col:第一次instant add column之前表上的列的个数。
  • dd::Column::se_private_data::default_null:标识instant column的默认值是否为NULL。
  • dd::Column::se_private_data::default:当instant column的默认值不是NULL时存储具体的默认值,column default value需要从InnoDB类型byte转换成“se_private_data”中的char类型。

载入数据字典

MySQL从系统表读取表定义时,会将instant column相关的信息载入到InnoDB的表对象“dict_table_t”和索引对象“dict_index_t”中。

  • dict_table_t::n_instant_cols:第一次instant add column之前的非虚拟字段个数(包含系统列)。
  • dict_index_t::instant_cols:用于标示是否存在Instant column。
  • dict_index_t::n_instant_nullable:第一次instant add column之前的可为NULL的字段个数。
  • dict_col_t::instant_default:存储instant列默认值及其长度。

记录格式

为了支持instant add column,针对COMPACT和DYNAMIC类型引入了新的记录格式,主要为了记录字段的个数信息。

  • 如果没有执行过instant add column操作,则表的行记录格式保持不变。
  • 如果执行过instant add column操作,则所有新的记录都会设置一个特殊的标记,同时在记录内存储字段的个数。

INSTANT_FLAG使用了info bits中的一个bit位,如果记录是第一次instant add column之后插入的,该flag被设置为1。

图1 记录格式

查询

查询的流程没有变化,关对于没有存储在记录中的instant column,直接填默认值即可。

插入

执行instant add column后,旧数据的格式没有变化,新插入的数据按照新格式存储。新纪录的info bits中的一个位被设置成了REC_INFO_INSTANT_FLAG,表示这个记录是instant add column之后创建的。