登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL 在线加索引时怎么判断 ALGORITHM 和 LOCK 选项

来源:17golang原创

时间:2026-09-08 08:25:06 393浏览 收藏

给 InnoDB 表在线新增二级索引时,先记住一个判断:ALGORITHM 决定 MySQL 用什么方式完成结构变更,LOCK 决定你允许它占用多大的并发空间。普通二级索引通常适合 ALGORITHM=INPLACE,并可尝试 LOCK=NONE;但它不是 INSTANT,也不能消除最后阶段的元数据锁等待。

要点速览
  • 新增 InnoDB 二级索引通常是 INPLACE,不是只改数据字典的 INSTANT。
  • LOCK=NONE 表示“不支持并发读写就失败”,不是强行把操作变成在线。
  • 生产变更前要同时看索引类型、写入量、磁盘临时空间和元数据锁等待。

先看加二级索引到底属于哪种在线 DDL

MySQL 8.4 手册把 COPYINPLACEINSTANT 分成三种实现路径。COPY 会复制表数据;INPLACE 不复制整张表的数据,但可能在原地重建结构;INSTANT 只改元数据,表数据不动。

对 InnoDB 普通二级索引,官方在线 DDL 表把它列为“支持 INPLACE、允许并发 DML、不是 INSTANT”。这就是为什么下面的语句通常比强制 COPY 更适合业务运行期间执行:

-- 普通二级索引要求尽量保持业务读写
ALTER TABLE orders
  ADD INDEX idx_orders_customer_created (customer_id, created_at),
  ALGORITHM=INPLACE,
  LOCK=NONE;

这里的 LOCK=NONE 是一个可验证的并发要求。若当前表结构、存储引擎或索引类型不支持它,语句应当报错,而不是悄悄降级成更重的锁模式。图1把表结构、并发写入和锁边界放在同一张图里,重点是理解关系,不是展示一次真实执行。

MySQL InnoDB 在线新增二级索引中 ALTER TABLE、数据页、并发 DML 与元数据锁的静态关系图
图1:从表结构域、并发写入域和锁边界看新增二级索引的在线 DDL 约束。

ALGORITHM 和 LOCK 应该怎么组合

这两个参数不是一回事。可以把 ALGORITHM 看成“实现路径”,把 LOCK 看成“并发合同”。在线加普通二级索引时,常见选择如下:

场景建议组合含义
必须保持读写可用INPLACE, LOCK=NONE不满足并发 DML 条件就失败,适合先演练再上线。
允许读但不允许写入INPLACE, LOCK=SHARED只在业务能接受写阻塞时使用。
默认交给 MySQL 判断DEFAULT, DEFAULT兼容性更宽,但不把并发承诺写死。
明确接受表复制COPY需要额外评估空间与 DML 影响,不是在线首选。

LOCK=EXCLUSIVE 会强制独占访问;它不是“更稳的 NONE”,而是主动放弃并发读写。对于 INSTANT 操作,MySQL 只允许 LOCK=DEFAULT,所以不要看到“默认算法”就推断所有锁选项都可用。

图2用三个静态域区分算法候选、并发约束和失败边界。真正的决策顺序是:先确认操作是否支持目标算法,再确认目标锁级别是否被该操作支持,最后才安排变更窗口。

MySQL ALTER TABLE 中 ALGORITHM=INPLACE、COPY 与 LOCK=NONE、SHARED、EXCLUSIVE、DEFAULT 的关系图
图2:ALGORITHM 负责实现路径,LOCK 负责并发要求,两者在不兼容时共同形成失败边界。

上线前先排除四个变更窗口风险

  1. 确认索引类别。普通二级索引和主键不是同一件事。主键改变会牵涉聚簇索引和数据重组,不能直接套用普通二级索引的经验。
  2. 确认短暂元数据锁。即使允许并发 DML,开始和结束阶段仍可能需要拿表级元数据锁。长事务、未提交事务或高峰期 DDL 都可能让它等待。
  3. 确认临时空间。在线建索引会使用排序和在线变更日志相关空间;并发写入过多时,日志超过 innodb_online_alter_log_max_size 也会失败。
  4. 把失败当成保护机制。如果业务不能接受写阻塞,宁可让 LOCK=NONE 报错,也不要让默认策略在无人观察时换成更宽松但更重的锁模式。
-- 先在同版本、同表结构环境确认语句不会隐式换成不接受的路径
ALTER TABLE orders
  ADD INDEX idx_orders_status_created (status, created_at),
  ALGORITHM=INPLACE,
  LOCK=NONE;

-- 上线前同时检查长事务、磁盘余量和业务低峰窗口

常见问题

加二级索引可以写 ALGORITHM=INSTANT 吗?

普通 InnoDB 二级索引创建不是只改元数据的操作,通常应使用 INPLACE;强写 INSTANT 会因操作不兼容而失败。

LOCK=NONE 是否代表完全不会被锁住?

不是。它要求并发读写能力必须满足,但短暂的元数据锁仍可能等待,长事务是常见原因。

为什么不直接省略 ALGORITHM 和 LOCK?

省略后由 MySQL 按操作能力选择默认策略,兼容性更宽;如果你对写入连续性有硬要求,显式写出 NONE 更容易让不满足条件的变更立即失败。

在线加索引失败后要先查什么?

先看错误是否指向算法或锁不兼容,再看元数据锁等待、临时空间和在线变更日志上限,最后确认是否有并发写入造成的约束冲突。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>