不是,默认不保证在线;必须显式指定algorithm=inplace和lock=none,且满足innodb引擎、无外键/全文索引、无长事务等全部前提,mysql才真正免锁加索引,否则报错而非静默降级。

MySQL 5.6+ 支持在线添加索引,但默认不保证无锁——必须显式指定 ALGORITHM=INPLACE 和 LOCK=NONE 才能真正避免阻塞读写。
ALTER TABLE ADD INDEX 默认是否在线?
不是。即使 MySQL 版本 ≥ 5.6,ALTER TABLE table_name ADD INDEX ... 默认仍可能触发 COPY 算法(全表拷贝),尤其在字段含默认值、是生成列、或引擎非 InnoDB 时。你看到“执行很快”,不代表没锁表——可能只是表小,锁时间短到没被监控捕获。
- 查当前行为:
SELECT @@version, @@innodb_file_per_table;,确保是 InnoDB 引擎且独立表空间开启 - 验证是否真在线:执行 DDL 同时,在另一会话跑
SHOW PROCESSLIST;,观察是否有Waiting for table metadata lock - 别信文档说的“自动选择”,MySQL 只在满足全部条件时才用
INPLACE,否则降级为COPY
ALGORITHM=INPLACE, LOCK=NONE 的硬性前提
这两个参数不是开关,而是承诺——MySQL 检查不通过就直接报错,不会静默降级。
- 仅支持 InnoDB 表;MyISAM 不支持
INPLACE - 不能对
FULLTEXT或SPATIAL索引使用 - 目标列不能有
DEFAULT值(包括隐式默认如NOT NULL但无显式DEFAULT) - 不能涉及生成列(
GENERATED)、虚拟列或列压缩 - TEXT/BLOB 字段必须指定前缀长度,例如
ADD INDEX idx_content (content(255))
大表加索引卡住的典型错误操作
500 万行以上表,跳过参数检查直接执行,大概率触发磁盘爆满、主从延迟飙升、甚至 OOM。
- 错误写法:
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);—— 没指定算法,MySQL 自行判断,高概率 fallback 到COPY - 正确写法:
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status) ALGORITHM=INPLACE, LOCK=NONE; - 先试运行:
ALTER TABLE orders ALGORITHM=INPLACE, LOCK=NONE, ADD INDEX idx_user_status (user_id, status);,失败就立刻停,别等 2 小时后才发现锁了 - 线上环境务必加超时控制:
SET SESSION lock_wait_timeout = 30;,避免 DDL 卡死连接
唯一索引失败时的常见陷阱
ADD UNIQUE INDEX 失败不总是因为语法错,更多是数据问题——而错误信息藏得深。
- 报错
ERROR 1062 (23000): Duplicate entry 'xxx' for key 'uk_email':说明已有重复值,必须先清理 - 报错
ERROR 1524 (HY000): Plugin 'validate_password' is not loaded:和密码插件冲突,与索引无关,别被误导 - 允许 NULL 值多次存在,所以
SELECT email FROM users WHERE email IS NULL;返回多行 ≠ 违反唯一性 - 想强制非空唯一,必须组合:
ALTER TABLE users MODIFY email VARCHAR(255) NOT NULL, ADD UNIQUE uk_email (email);
真正难的不是写对那条 SQL,而是判断当前表结构是否满足 INPLACE 条件、预估执行窗口、以及准备好回滚方案——这些没法靠 EXPLAIN 看出来,得靠 INFORMATION_SCHEMA.COLUMNS 和实际测试。











