ALTER TABLE添加索引卡住因锁表重建,大表应优先用ALGORITHM=INPLACE, LOCK=NONE;CREATE INDEX与ADD INDEX语义等价但场景不同;函数WHERE使索引失效。

ALTER TABLE 添加索引时,为什么执行卡住或超时?
常见于大表(千万级以上)直接 ALTER TABLE ADD INDEX,MySQL 会锁表并重建整张表,期间写入阻塞、查询变慢,甚至触发 Lock wait timeout exceeded 错误。
- 生产环境优先用
ALGORITHM=INPLACE, LOCK=NONE(5.6+ 支持),但仅对某些操作生效,比如添加二级索引;主键或全文索引不支持无锁 - 确认存储引擎:InnoDB 支持大部分在线 DDL,MyISAM 一律全表拷贝锁表
- 提前在低峰期执行,并监控
SHOW PROCESSLIST中的altering table状态 - 更稳妥的方式是用
pt-online-schema-change工具,它通过影子表+触发器实现真正无锁
CREATE INDEX 和 ALTER TABLE ADD INDEX 有什么实际区别?
语义上几乎等价,底层都调用相同 DDL 流程,但使用场景和可读性不同。
-
CREATE INDEX idx_name ON table_name (col)只能建索引,不能改表结构,语法更聚焦、意图明确 -
ALTER TABLE table_name ADD INDEX idx_name (col)属于表结构变更命令,适合批量操作(比如同时加索引+改列类型) - 两者在 InnoDB 中生成的 B+ 树结构、查询行为完全一致,性能无差异
- 注意:如果索引名已存在,
CREATE INDEX报错ERROR 1061 (42000): Duplicate key name;ALTER TABLE ... ADD INDEX同样报错,不会静默覆盖
WHERE 条件含函数或表达式,索引还能用上吗?
绝大多数情况下不能——MySQL 无法对计算后的结果复用索引的有序性。
- 错误示例:
WHERE YEAR(create_time) = 2023→create_time列上的索引失效 - 正确写法:
WHERE create_time >= '2023-01-01' AND create_time ,可走范围扫描 - 类似陷阱:
WHERE UPPER(name) = 'ABC'、WHERE col + 1 = 100,都会跳过索引 - 例外:MySQL 8.0+ 支持函数索引(
CREATE INDEX idx ON t ((UPPER(name)))),但需显式创建,且只对指定函数有效
联合索引字段顺序怎么排才不白建?
顺序决定索引能否命中、以及能支持哪些查询模式,核心是「最左前缀匹配」原则。
- 建了
INDEX idx_a_b_c (a, b, c),以下查询可用索引:WHERE a = ?、WHERE a = ? AND b = ?、WHERE a = ? AND b = ? AND c = ? - 但
WHERE b = ?或WHERE b = ? AND c = ?无法使用该索引(缺少最左列a) - 高选择性列(如用户 ID)放前面,低选择性列(如性别、状态)放后面;排序/分组字段若与 WHERE 共用,也应前置
- 避免冗余:已有
(a, b)索引,再单独建(a)索引意义不大(除非a查询极频繁且b值很长,影响索引体积)
EXPLAIN 验证实际执行计划,而不是只看是否“有索引”。










