MySQL建索引需严格校验语法、字段与表名;优先用ALTER TABLE ADD INDEX;复合索引顺序须匹配查询条件;避免冗余索引;大表操作选低峰期;唯一索引承载约束语义;建索引后需ANALYZE TABLE更新统计信息。

CREATE INDEX 语法写错会直接报错,不是静默失败
MySQL 对 CREATE INDEX 的语法很敏感,尤其字段名、表名、索引类型稍有拼写或大小写不一致(在区分大小写的文件系统上),就会报 ERROR 1146 (42S02): Table doesn't exist 或 ERROR 1054 (42S22): Unknown column。别急着怀疑权限,先核对三件事:
-
SHOW TABLES确认表名完全匹配(含数据库前缀,如mydb.users) -
DESCRIBE table_name或SHOW COLUMNS FROM table_name看字段名是否带反引号、是否真存在 - 单列索引不用写
USING BTREE,但复合索引里如果漏了括号,比如写成CREATE INDEX idx ON t a,b(缺(a,b)),会报语法错误
WHERE 条件里用不到的字段加索引纯属浪费
索引不是越多越好。比如表有 user_id、status、created_at 三个字段,但所有查询都是 WHERE status = ?,那给 created_at 单独建索引几乎没用。真正该做的是:
- 用
EXPLAIN SELECT ...看key列是否命中现有索引 - 复合索引顺序很重要:
WHERE status = ? AND created_at > ?应建INDEX(status, created_at),反过来则可能失效 - 如果经常
ORDER BY created_at且带LIMIT,把created_at放复合索引末尾能避免 filesort
ALTER TABLE ADD INDEX 比 CREATE INDEX 更常用,但锁表风险更高
虽然 CREATE INDEX idx ON t(col) 和 ALTER TABLE t ADD INDEX idx(col) 效果一样,但实际运维中更倾向后者,因为它是 DDL 标准写法,工具链(如 pt-online-schema-change)也默认识别它。不过要注意:
- MySQL 5.6+ 支持
ALGORITHM=INPLACE,但加二级索引仍需短暂锁表;5.7+ 对普通 B-tree 索引支持真正的 online DDL,前提是没指定LOCK=SHARED或LOCK=EXCLUSIVE - 大表加索引务必在低峰期操作,否则
SELECT可能被阻塞几秒到几分钟,取决于数据量和磁盘 I/O - 不要在从库上直接建索引——主从复制本身不传索引变更,从库索引需手动同步,否则
SHOW CREATE TABLE结果不一致
唯一索引和主键索引不能简单互换
有人看到 email 字段要查得快,顺手加个 UNIQUE INDEX,结果插入重复值时程序直接抛 Duplicate entry 'x@y.z' for key 'idx_email'。这不是性能问题,是语义问题:
-
UNIQUE INDEX是约束 + 索引,会拒绝重复值;INDEX只加速查询,不拦数据 - 主键(
PRIMARY KEY)自动是唯一且非空的,还隐式作为聚簇索引;普通唯一索引是二级索引,回表成本略高 - 如果业务本就要求 email 唯一,应该在建表时定义
email VARCHAR(255) UNIQUE,而不是事后补索引——DDL 更清晰,应用层错误也更明确
最常被忽略的一点:索引生效依赖统计信息,而 ANALYZE TABLE 不会自动触发。表数据批量导入后,即使加了索引,优化器也可能因过时的行数估算而选错执行计划。别只盯着建索引,记得跑一次 ANALYZE TABLE your_table。


















