导读:本期聚焦于小伙伴创作的《MySQL加索引会导致锁表吗?详解Online DDL原理与生产环境最佳实践》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《MySQL加索引会导致锁表吗?详解Online DDL原理与生产环境最佳实践》有用,将其分享出去将是对创作者最好的鼓励。

MySQL加索引会导致数据库锁表吗?

在数据库开发和运维中,“加索引是否会导致锁表”是一个非常经典的疑问。很多开发者在生产环境加索引时都遇到过业务阻塞、告警频发的情况,从而对加索引操作心生畏惧。

简单来说:在MySQL 5.6及以上版本中,使用InnoDB引擎给表加普通索引,默认不会锁表(允许并发DML操作);但在操作的准备和提交阶段会有极短的锁;而在MySQL 5.5及更早版本中,加索引确实会导致锁表。

下面我们来详细剖析这背后的原理以及生产环境中的最佳实践。

一、历史背景:MySQL 5.5及以前的锁表时代

在MySQL 5.5及之前的版本中,DDL(数据定义语言,如ADD INDEX)采用的是COPY算法。其执行过程如下:

  1. 对原表加排他锁,此时原表完全不可读写(锁表)。

  2. 创建一个与原表结构相同的临时表,并在临时表上添加新索引。

  3. 将原表中的数据逐行拷贝到临时表。

  4. 删除原表,将临时表重命名为原表名。

  5. 释放排他锁。

在这个过程中,由于数据拷贝需要耗费大量时间,特别是对于千万级的大表,拷贝时间可能长达数十分钟甚至数小时,这期间业务的所有增删改查都会被阻塞,对线上业务是毁灭性的打击。

二、现代机制:MySQL 5.6+的Online DDL

为了解决DDL锁表的问题,MySQL 5.6引入了Online DDL(在线数据定义)机制。对于添加普通索引(SECONDARY INDEX),InnoDB默认使用INPLACE算法,并且不排斥DML操作。

其核心流程如下:

  1. 准备阶段:短暂地获取MDL(元数据锁)的排他锁,此时新请求会被阻塞,但这个阶段非常快。

  2. 执行阶段:释放MDL排他锁,降级为MDL共享锁。此时允许并发的DML(INSERT/UPDATE/DELETE)操作。InnoDB会在线构建索引,同时将执行期间产生的DML变更写入一个Online Log(在线日志)中。

  3. 提交阶段:再次短暂获取MDL排他锁,将Online Log中的变更应用到新索引上,更新元数据,然后释放锁。

因此,在绝大多数情况下,我们说MySQL 5.6+加索引是不锁表的。你可以显式地指定算法和锁模式来确保安全:

-- 明确指定使用INPLACE算法,且不阻塞DML操作
ALTER TABLE my_table ADD INDEX idx_name (column_name), ALGORITHM=INPLACE, LOCK=NONE;

三、为什么有时候加了索引依然感觉“锁表”了?

虽然Online DDL在理论上不锁DML,但在实际生产环境中,加索引依然可能引发业务阻塞,通常是由以下几个原因造成的:

1. MDL(元数据锁)等待导致“假锁表”

Online DDL在开始和结束阶段需要获取MDL排他锁。如果此时有一个长事务正在对该表执行查询(持有MDL共享锁),DDL操作会被阻塞,等待该事务释放锁。更严重的是,DDL一旦等待MDL锁,它自身也会持有MDL共享锁,这会导致后续所有试图访问该表的新DML请求全部被阻塞,形成链式等待,表面看起来就像锁表了一样。

-- 查看当前正在执行的MDL锁等待情况(MySQL 5.7+)
SELECT * FROM sys.schema_table_lock_waits;

-- 查找长事务并Kill掉阻塞源
SHOW PROCESSLIST;

2. 主键/唯一索引的创建依然可能锁表

Online DDL对普通索引支持完美,但如果添加的是主键索引唯一索引,情况会复杂得多。因为主键即聚簇索引,修改主键意味着要重建整张表。虽然InnoDB也支持INPLACE方式创建主键,但在某些版本和场景下,仍可能退化成COPY算法,或者需要更长时间的MDL排他锁。

3. 硬件资源瓶颈

加索引是一个极其消耗CPU和磁盘I/O的操作。在大表上建索引时,可能会把磁盘I/O打满,导致正常的业务SQL执行变慢,引发数据库连接池耗尽,表现出来的现象和锁表非常相似。

四、生产环境安全加索引的最佳实践

为了避免加索引引发线上事故,建议遵循以下实践:

  1. 避开业务高峰期:尽管有Online DDL,依然建议在低峰期操作,避免I/O争抢和潜在的MDL锁冲突。

  2. 检查长事务:在执行DDL前,先执行 SHOW PROCESSLIST 确保没有长时间运行的查询或事务。

  3. 设置锁等待超时:如果DDL长时间获取不到MDL锁,不要让它一直阻塞后续请求,可以设置较短的锁等待超时时间,让DDL快速失败。

-- 设置当前会话的锁等待超时时间为5秒(默认通常是50秒)
SET SESSION lock_wait_timeout = 5;

-- 执行加索引操作,如果5秒内拿不到MDL锁则自动放弃
ALTER TABLE my_table ADD INDEX idx_col (col_name), ALGORITHM=INPLACE, LOCK=NONE;
  1. 使用第三方无锁变更工具:对于超大表,建议使用 gh-ostpt-online-schema-change 等工具。它们的核心原理是通过创建影子表、在影子表上执行DDL、然后通过Binlog或触发器同步增量数据,最后通过原子Rename表来切换,对业务几乎零影响。关于这些工具的更多详细信息,你可以参考 www.ipipp.com 上的相关技术文档。

五、总结

MySQL加索引本身在5.6版本以后已经通过Online DDL实现了“在线”添加,不再长时间锁表。但我们必须警惕由于长事务导致的MDL锁互等以及资源消耗过大引发的连锁反应。只要做好操作前的检查,合理控制超时时间,或者在超大表场景下使用专业的变更工具,就能安全、平滑地完成索引添加工作。

MySQL加索引锁表Online DDL元数据锁生产环境优化

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。