MySQL上亿大表,如何新增字段?

0 阅读3分钟

本文首发于公众号:托尼学长,立个写 1024 篇原创技术面试文章的flag,欢迎过来视察监督~

兄弟们,面试官要是再问你“MySQL上亿大表,如何新增字段”,你就果断地告诉他,直接新增就可以,不用说别的废话!

我来解释一下为什么这么做。

在MySQL5.5及以前的版本中,在上亿大表执行新增字段这样的DDL操作时会锁表,并且锁表时间可能会长达数小时,导致DML操作select insert update delete语句被阻塞的问题。‌

如果系统不允许停服、业务需要 7×24 小时运行的话,就得通过pt-online-schema-change(Percona Toolkit)之类的工具实现无锁新增字段了,它的核心原理是 “影子表 + 触发器 + 分批拷贝”,全程不阻塞读写。

而到了MySQL 5.6 及以上版本就引入在线DDL的技术了,实现MySQL在执行大数据量表结构变更(包括新增字段)时,能够尽量减少对表的锁定,允许DML操作并发进行,从而提高了服务的可用性。‌

那MySQL 5.6版本是什么时候发布的呢?2013年,已经发布12年,整整12年了啊,难道面试官还活在上个世纪吗?

我们再把话题说出来,在线DDL可以通过这种方式进行配置。

图片

其中,ALGORITHM=INPLACE‌ 表示原地修改表结构,操作直接在原表数据上进行,无需创建临时表或复制数据。这种方式可以避免因数据拷贝带来的额外存储空间消耗和 I/O 压力,提升操作效率。‌

LOCK=NONE‌ 表示在执行 DDL(新增字段)操作时,不阻塞并发的DML操作select insert update delete等,几乎不影响线上业务的正常运行。‌

而且,关键的是而且,到了MySQL8.0版本中,又对在线DDL进行大幅优化,主要包括如下几点。

1、这是MySQL 8.0最为核心的一个优化,那就是在亿级数据表中新增 NOT NULL + 默认值字段,耗时从 “小时级” 优化到了 “秒级”。

其原理为,在MySQL 5.6中必须使用ALGORITHM=COPY(全表拷贝),逐行为每条记录写入默认值,亿级表操作耗时小时级;全程加表级写锁,业务读写完全阻塞,必须在停机窗口执行;而且拷贝全表数据导致磁盘 IO 暴涨,极易引发数据库性能雪崩。

而在MySQL 8.0中,支持该场景下的ALGORITHM=INPLACE,仅修改元数据字典(默认值存储在字典中,不更新历史数据),秒级完成;历史数据读取时动态返回默认值,无需逐行更新,彻底避免全表拷贝;

2、原子DDL特性‌,MySQL 8.0 引入了原子 DDL,确保在新增DDL 操作要么完全成功,要么完全回滚,不会留下中间状态。

3、锁机制优化,实现更精细的锁粒度,彻底避免业务阻塞。MySQL 5.6版本中,即使新增 NULL 字段指定LOCK=NONE,仍会在 DDL 启动、结束阶段加短暂的表级读锁,导致写操作排队。

而在MySQL 8.0版本中,仅在 “元数据校验阶段” 加毫秒级元数据锁,执行阶段完全释放,读写操作无感知;并将锁粒度从 “表级” 降至 “列级”,新增字段仅影响目标列,不阻塞其他列的读写。

当你将这些技术点跟面试官说完,想让他不佩服你都不行!