数据库ALGORITHM = INSTANT 特性研究过程

一. 背景


在日常工作中添加大表字段是个正常不过的操作,偶然发现团队中发现同事大量使用 ALGORITHM = INSTANT 更新字段,根据固有的理解,字段的更新必然会涉及到表结构的更改,印象中数据库会加入MDL锁去保证表数据的一致性。

但是听说在Mysql8.0+特性中,表明在更新字段的时候此方法不会导致锁表,因为这是一个在线的DDL的操作方式。后续带着疑问查询了大量的文章未果,依然没有理解其中的原理,固写下文研究过程。

二. 疑问点


例如下面的DDL方式

sql 复制代码
ALTER TABLE users ADD COLUMN age INT DEFAULT 0 COMMENT '年龄', ALGORITHM=INSTANT;

在结尾处使用了【ALGORITHM=INSTANT】的字段表述方式,即可避免锁表。

orz. 是什么东西,难不成是传说中的"多级&叠加表"设计?我猜想:数据依然是老数据,但是新表是新表,所以查询引擎层会append一些新表结构的字段回去。

上面颠覆了我的认知。orz. 接下来的研究验证了我的猜想。

三. 研究过程


我查询了许多文章的表述,但是最终得到的更多是【Mysql8.0+特性】。显然这样的结论并不能直接说服我们对技术的渴望,偶然看到一篇帖子,恍然大悟。

记录在淘宝的【数据库内核技术2020年3月】的报刊中,我们发现研究者对这项特性是这样描述的:

在实现上,MySQL并没有在系统表中记录多个版本的schema,而是非常取巧的扩展了存储格式。在已有的info bits区域和新增的字段数量区域记录了instant column信息,instant add column之前的数据不做任何修改,之后的数据按照新格式存储。同时在系统表的private_data字段存储了instant column的默认值信息。查询时,读出的老记录只需要增加instant column默认值,新记录则按照新的存储格式进行解析,做到了新老格式的兼容。当然,这种实现方式带来的限制就是只能顺序加字段。

看完后,总结以下几点

  1. 在原有的数据表结构和新增的字段记录了【instant column】字段信息。
  2. 旧数据查询的时候会补充【instant column】默认值,新数据按新的结构存储。

对于大佬的总结,是根据一篇mysql的官网技术worklog来进行解读的

该技术第五点有个这样的阐述

sql 复制代码
For "old" rows, the default value will be looked up from the new system
tables and appended before return to server.

翻译过来就是:【对于"旧"行,将从新系统中查找默认值表格并在返回服务器之前附加】

这句话验证了我的猜想:表里存在的旧数据,在数据返回到服务器将新的字段进行append回去,去展示对应的完整数据行。

那也就是我们在操作数据的时候,使用了ALGORITHM = INSTANT在表里使用了DDL的方式操作,那么我们将不会关注元数据的更改情况,也就是不用关心锁表。

但是也提供了【INPLACE&FORCE 】原来的复制表的方式来更新内部表,也就是锁表的方式。

关于Instant算法技术内幕原理

对于instant算法,可看上图

假设本身存在的一张表t1 , 先存在 a字段,插入一条数据x,此时存在了x(1) 【1 = 当前的列号情况】

现在ADD COLUMN更新表增加了b字段,再次插入一条数据y,此时存在数据x(1 + 1') + y(2)。【其中1' = append 1列的意思,同下】最新数据y将使用所有列的情况,而x旧数据只保存了a列的字段,并没有b的,所以需要组装返回

再次ADD COLUMN更新表增加了c字段,再次插入一条数据z,此时存在的数据x(1+2')+y(2+1')+z(3)。新增了c字段后,同上步骤,此时x将append 【bc列】的组装返回,y将append【c列】,而x会使用所有列的情况。

表达的方式类似如图最后一张。

学习到其他大佬的对sql执行过程输出,观察到在使用instant字段后对其表进行数据新增,其新增数据会在bit字段设置为1来代表数据是instant之后的。

因为对于内部执行流程 rec_set_instant_flag_new函数在记录的Info bits字段设置,REC_INFO_INSTANT_FLAG,会表示这个记录是instant add column之后创建的。

使用的注意点

  1. ALGORITHM = INSTANT 不能与 LOCK 子句一起使用,如果指定了 INSTANT,并且 LOCK=NONE/SHARED/EXCLUSIVE如果同时指定了 LOCK=DEFAULT,则会引发 ER_WRONG_USAGE 错误。但是,如果同时指定了 LOCK=DEFAULT,则可以。
  2. ADD COLUMN 可能会立即完成,因此我们可能不会期望立即进行 ADDCOLUMN 去修复损坏的索引
  3. 此工作日志不支持具有全文索引的表。
  4. 对于 EXCHANGE PARTITION,为了简化逻辑,如果分区或要交换的表是即时的,那么该操作将被拒绝错误 ER_PARTITION_EXCHANGE_DIFFERENT_OPTION。
  5. 对于使用它进行索引的创建或者更新,算法会被降级【ALGORITHM=INPLACE】,此时涉及到锁表,进行数据文件的物理修改。
  6. INPLACE 算法原理(GPT):
    1. 扫描表数据,构建索引结构。
    2. 允许并发 DML 操作(如 INSERT/UPDATE/DELETE),但某些阶段可能短暂阻塞 DDL。
    3. 最终替换旧表文件,完成索引创建。

四. 总结


使用Instant字段对元数据的操作(增加/修改字段和注释等),会将旧数据新增的字段列号只能附加在表的最后,而新数据将使用新表的数据方式存储。这是一个技术突破的东西。

仔细一看,mysql的描述感谢了Tencent的付出,腾讯哥还是厉害。他们主要的优化点是【ALTER TABLE .. ADD COLUMN 可以立即完成,不需要太多的 IO 和等待时间】。

这个特性的诞生,意味着大家对于新增字段大表的数据结构需要去增加字段,不会像之前那样操作锁表,mysql8.0+版本随意放心食用。

五. 感谢


阿里数据库内核2020-03报刊

数据库Instant特性

相关推荐
uhakadotcom14 分钟前
BentoML远程代码执行漏洞(CVE-2025-27520)详解与防护指南
后端·算法·面试
xmyLydia40 分钟前
我做了一个代码生成器:Spring Boot + Angular 全自动构建
后端
supermfc1 小时前
Docker方式离线部署OpenWebUI
后端·deepseek
橘猫云计算机设计1 小时前
基于django云平台的求职智能分析系统(源码+lw+部署文档+讲解),源码可白嫖!
数据库·spring boot·后端·python·django·毕业设计
码农小站1 小时前
MyBatis-Plus 表字段策略详解:@TableField(updateStrategy) 的配置与使用指南
java·后端
技术小丁1 小时前
使用PHP将PDF转换为图片(windows + PHP + ImageMagick)
后端
李憨憨1 小时前
深入探究MapStruct:高效Java Bean映射工具的全方位解析
java·后端
仰望星空的打工人1 小时前
若依改用EasyCaptcha验证码
后端
雷渊1 小时前
通俗易懂的来解释倒排索引
java·后端·面试
知其然亦知其所以然1 小时前
面试官狂喜!我用这 5 分钟讲清了 ThreadPoolExecutor 饱和策略,逆袭上岸
java·后端·面试