各位观众老爷们,大家好!我是今天的主讲人,今天咱聊聊MySQL里让人又爱又恨的DDL(Data Definition Language)操作,尤其是如何优雅地、不阻塞业务地进行在线DDL。
一、DDL,你这磨人的小妖精
DDL,简单来说,就是用来定义和修改数据库结构的语句,比如CREATE TABLE,ALTER TABLE,DROP TABLE等等。这些操作,在数据库的世界里,就像盖房子,动辄拆墙砌梁,对数据库的影响可不小。
传统的DDL操作,大部分情况下会锁表,导致这段时间内,应用程序无法进行读写操作。想象一下,你的电商网站正在搞大促,用户正疯狂下单,结果你突然执行了一个ALTER TABLE,把表锁住了,用户只能眼巴巴地看着屏幕,下单失败,那损失可就大了去了!
所以,我们需要找到一种办法,既能修改表结构,又能保证业务的正常运行,这就是所谓的“在线DDL”。
二、在线DDL的进化史
MySQL的在线DDL技术,也不是一开始就这么完善的,它也经历了漫长的进化过程。
-
MySQL 5.1及更早:Copy Table
这是最原始的方式,创建一个新的表,将旧表的数据复制到新表,然后删除旧表,重命名新表。这种方式的优点是简单粗暴,缺点也很明显:
- 耗时巨大:数据复制需要大量时间,尤其是对于大表。
- 需要双倍空间:在复制期间,需要额外的空间来存储新表。
- 数据不一致:在复制期间,旧表上的数据变更无法同步到新表,需要额外的手段来保证数据一致性。
这种方式,基本告别了“在线”二字,生产环境基本不敢用。
-
MySQL 5.5:Inplace DDL (仅部分操作)
MySQL 5.5引入了Inplace DDL,它允许在原始表上直接进行修改,而不需要复制数据。这大大提高了DDL的效率。但需要注意的是,MySQL 5.5的Inplace DDL只支持部分操作,例如:
- 增加或删除索引(但不支持改变索引类型)
- 改变VARCHAR/VARBINARY的长度
- 添加或删除列(但不支持改变列的数据类型)
即使是Inplace DDL,也可能会锁表,但锁的时间大大缩短了。
-
MySQL 5.6:Online DDL
MySQL 5.6对Inplace DDL进行了增强,引入了真正的Online DDL。它允许在修改表结构的同时,允许应用程序进行读写操作。它是通过以下机制实现的:
- 允许并发DML:在DDL执行期间,允许对表进行读写操作。
- ROW_LOG:将DDL执行期间的DML操作记录到row log中。
- DDL完成后应用ROW_LOG:DDL完成后,将row log中的操作应用到新表结构中,以保证数据一致性。
MySQL 5.6的Online DDL支持更多的操作,例如:
- 改变列的数据类型
- 增加或删除索引
- 修改表属性
虽然是Online DDL,但仍然存在一些限制,例如:
- 不支持重命名列
- 不支持修改主键
-
MySQL 5.7及更高版本:更强大的Online DDL
MySQL 5.7及更高版本,对Online DDL进行了进一步的优化,支持更多的操作,例如:
- 重命名列
- 优化了ROW_LOG的性能
- 引入了ALGORITHM和LOCK选项,允许更细粒度的控制DDL的行为
总的来说,MySQL的在线DDL技术一直在不断进步,越来越强大,越来越灵活。
三、ALGORITHM和LOCK:掌控DDL的利器
MySQL 5.6及更高版本,引入了ALGORITHM和LOCK选项,允许我们更精细地控制DDL的行为。
-
ALGORITHM选项
ALGORITHM选项用于指定DDL操作的算法,它有以下几个可选值:
- DEFAULT:由MySQL自动选择算法。通常情况下,MySQL会选择最快的算法,但可能会锁表。
- COPY:使用Copy Table的方式进行DDL操作。
- INPLACE:使用Inplace DDL的方式进行DDL操作。
- INSTANT:(MySQL 8.0.12及以上) 几乎立即完成的操作,只修改元数据,不涉及数据拷贝或阻塞。 适用于添加列(允许为NULL且有默认值)。
选择不同的ALGORITHM,会影响DDL的性能和并发性。
-
LOCK选项
LOCK选项用于指定DDL操作的锁级别,它有以下几个可选值:
- DEFAULT:由MySQL自动选择锁级别。通常情况下,MySQL会选择最小的锁级别,以保证最大的并发性。
- NONE:不加任何锁。如果DDL操作与并发的DML操作冲突,DDL操作会失败。
- SHARED:允许并发的读操作,但阻塞写操作。
- EXCLUSIVE:阻塞所有的读写操作。
选择不同的LOCK级别,会影响DDL的并发性。
四、实战演练:在线DDL的正确姿势
理论讲了一大堆,现在让我们来点实际的,通过一些例子,来看看如何正确地使用在线DDL。
场景一:添加一个允许为NULL且有默认值的列
假设我们有一个users
表,需要添加一个email
列,允许为NULL,默认值为空字符串。
ALTER TABLE users
ADD COLUMN email VARCHAR(255) DEFAULT '' NULL,
ALGORITHM=INSTANT, LOCK=NONE;
这个操作几乎是瞬间完成的,因为它只修改了表的元数据,不需要复制数据或加锁。
场景二:添加一个索引
假设我们需要在users
表的username
列上添加一个索引。
ALTER TABLE users
ADD INDEX idx_username (username),
ALGORITHM=INPLACE, LOCK=NONE;
这个操作使用Inplace DDL,并尽量不加锁。如果DDL操作与并发的DML操作冲突,DDL操作会失败。
场景三:修改VARCHAR列的长度
假设我们需要将users
表的username
列的长度从50修改为100。
ALTER TABLE users
MODIFY COLUMN username VARCHAR(100),
ALGORITHM=INPLACE, LOCK=NONE;
同样,这个操作使用Inplace DDL,并尽量不加锁。
场景四:修改列的数据类型
假设我们需要将users
表的age
列的数据类型从INT修改为BIGINT。
ALTER TABLE users
MODIFY COLUMN age BIGINT,
ALGORITHM=INPLACE, LOCK=NONE;
这个操作也使用Inplace DDL,并尽量不加锁。但需要注意的是,修改列的数据类型可能会导致数据丢失,需要谨慎操作。
五、在线DDL的注意事项
在线DDL虽然强大,但也不是万能的,在使用时需要注意以下几点:
- 监控DDL的进度:可以使用
SHOW PROCESSLIST
命令来查看DDL的进度。 - 监控数据库的性能:在线DDL会消耗一定的系统资源,需要监控数据库的CPU、内存、IO等指标,以确保数据库的性能不受影响。
- 选择合适的ALGORITHM和LOCK:根据实际情况,选择合适的ALGORITHM和LOCK,以平衡DDL的性能和并发性。
- 备份数据:在执行DDL操作之前,一定要备份数据,以防止意外情况发生。
- 小步快跑:尽量避免一次性修改大量的表结构,可以将大的DDL操作分解为小的DDL操作,逐步进行。
- 仔细测试:在生产环境执行DDL操作之前,一定要在测试环境进行充分的测试。
六、工具推荐:gh-ost和pt-online-schema-change
除了MySQL自带的Online DDL,还有一些第三方工具可以帮助我们更方便地进行在线DDL操作,例如:
- gh-ost:由GitHub开源的一款在线DDL工具,它通过创建一个ghost表,将原表的数据复制到ghost表,然后将原表的DML操作同步到ghost表,最后切换ghost表和原表。gh-ost的优点是性能高、并发性好,缺点是配置复杂。
- pt-online-schema-change:是Percona Toolkit中的一款在线DDL工具,它与gh-ost的原理类似,也是通过创建一个影子表,将原表的数据复制到影子表,然后将原表的DML操作同步到影子表,最后切换影子表和原表。pt-online-schema-change的优点是配置简单,缺点是性能相对较低。
这两个工具都是非常强大的在线DDL工具,可以根据实际情况选择使用。
七、总结
在线DDL是MySQL进阶编程中非常重要的一环,掌握在线DDL技术,可以让我们更优雅地修改表结构,而不会影响业务的正常运行。希望今天的讲座能帮助大家更好地理解和使用在线DDL。
记住,DDL虽好,可不要贪杯哦! 谨慎操作,方能保证数据的安全和稳定。 谢谢大家!