能,但必须显式指定ALGORITHM=INPLACE和LOCK=NONE,否则MySQL易退化为锁表;加索引卡住SELECT实为MDL锁阻塞,非索引本身读锁表。

能,但必须显式控制 ALGORITHM 和 LOCK 参数,否则 MySQL 很可能悄悄退化为锁表模式——尤其是当有长事务、外键或未清理重复值时。
为什么加索引还会卡住 SELECT?
不是索引本身在“读锁表”,而是元数据锁(MDL)在阻塞。只要 ALTER TABLE 还没拿到 MDL 写锁,所有后续对这张表的 SELECT(哪怕只查一行)都会排队等待,直到 ALTER 完成或超时。
- 典型现象:
SHOW PROCESSLIST里看到一堆Waiting for table metadata lock - 真正瓶颈常不在索引构建,而在 Prepare 阶段等 MDL:前面有个慢查询或未提交事务占着表,ALTER 就一直挂起
-
LOCK=NONE只保证 DML 并发,DDL 自身仍需极短 MDL;LOCK=SHARED则连写都阻塞,LOCK=EXCLUSIVE就是传统锁表
必须显式写全参数,不能依赖 DEFAULT
MySQL 的 LOCK=DEFAULT 或 ALGORITHM=DEFAULT 在大表上极易降级:比如存在外键、触发器、TEXT 列参与索引,或 innodb_file_per_table=OFF,都会导致它自动切回 ALGORITHM=COPY,即重建整张表。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 安全写法(添加二级索引):
ALTER TABLE my_table ADD INDEX idx_col (col), ALGORITHM=INPLACE, LOCK=NONE; - 唯一索引额外要求:必须先清重,否则直接报
ERROR 1062 (23000): Duplicate entry 'xxx' for key 'uk_col',且不提示行号 - 验证是否真走 Online DDL:
EXPLAIN FORMAT=JSON SELECT 1 FROM my_table LIMIT 1;执行后看"alter_algorithm": "inplace"和"lock": "none"
当 Online DDL 不适用时,换 gh-ost 或 pt-online-schema-change
不是所有场景都能靠 ALGORITHM=INPLACE 解决。比如表含外键、要改列类型、或从库延迟已敏感,Online DDL 的 Row Log 回放可能拖太久,反而放大风险。
-
gh-ost更可控:不依赖触发器,通过 binlog 解析+异步应用变更,适合超大表(>5000 万行)和高可用要求场景 -
pt-online-schema-change依赖触发器,若原表已有触发器则失败;且要求innodb_flush_log_at_trx_commit=1,否则可能丢数据 - 共性前提:主从复制正常、磁盘空间充足(临时表/日志目录)、
innodb_online_alter_log_max_size足够大(默认 128MB,大表建议调至 512MB)
最容易被忽略的一点:加索引前不做 SELECT col, COUNT(*) FROM t GROUP BY col HAVING COUNT(*) > 1 查重,就直接跑 ADD UNIQUE KEY——90% 的失败都卡在这一步,而且错误信息根本不告诉你哪几行冲突。

















