ALTER TABLE加索引更常用,因其支持在线操作且锁控制更好;CREATE INDEX在低版本或MyISAM上易阻塞写入。需注意索引类型、列序、前缀长度及避免函数操作导致失效。

ALTER TABLE 加索引比 CREATE INDEX 更常用
MySQL 里给现有表加索引,ALTER TABLE 是更主流的做法,不是因为 CREATE INDEX 不行,而是它不支持在线加索引(5.6+ 的 ALTER TABLE ... ALGORITHM=INPLACE 才真正支持),而 ALTER TABLE 在多数版本中能更好控制锁行为。
常见错误是直接写 CREATE INDEX idx_name ON table_name (col),结果在低版本或某些存储引擎(如 MyISAM)上阻塞写入太久,甚至被 DBA 拦下来。
-
ALTER TABLE t ADD INDEX idx_status (status)—— 默认加 B-tree 索引,最安全 - 想加唯一索引?用
ADD UNIQUE INDEX,别漏掉UNIQUE - 加联合索引注意列顺序:
ADD INDEX idx_type_created (type, created_at),type必须在前才能高效用于WHERE type = ? - 如果表很大(千万级以上),务必加
ALGORITHM=INPLACE, LOCK=NONE(仅 5.6+ InnoDB 支持),否则会锁全表
索引字段选错会导致完全失效
加了索引但查询还是慢?大概率是字段选错了。MySQL 只有在 WHERE、JOIN、ORDER BY、GROUP BY 中实际参与比较的列才可能走索引。
典型翻车场景:
- 对
TEXT或长VARCHAR字段直接建索引:必须指定前缀长度,比如ADD INDEX idx_title (title(100)) - 在索引列上用函数:
WHERE YEAR(created_at) = 2024——created_at有索引也用不上,改写成WHERE created_at >= '2024-01-01' AND created_at -
LIKE '%abc'开头通配 —— 索引无法做最左匹配,LIKE 'abc%'才行 - 隐式类型转换:
WHERE user_id = '123'(user_id是INT)—— 会放弃索引,改成WHERE user_id = 123
查看索引是否生效不能只看 EXPLAIN 的 type=ref
EXPLAIN 输出里 type 是 ref 或 range 只说明用了索引,不代表高效。关键要看 key_len、rows 和 Extra。
容易忽略的点:
-
key_len显示 5,但字段是VARCHAR(255)—— 说明只用了前缀索引的前几个字节,可能没覆盖实际查询长度 -
rows值远大于实际返回行数?说明 MySQL 估算偏差大,可能需要ANALYZE TABLE更新统计信息 -
Extra出现Using filesort或Using temporary—— 即使走了索引,排序/分组仍可能走磁盘临时表,得看ORDER BY是否命中索引最左前缀 - 联合索引
(a,b,c),WHERE a=1 AND c=3只能用上a,c被跳过 ——EXPLAIN的key_len会暴露这点
删除无效索引比加索引还重要
线上表索引越多,写入越慢,而且很多“历史索引”早就不被查询使用了。不要以为加了就完事,定期清理才是常态。
判断一个索引是否该删:
- 查
information_schema.STATISTICS看INDEX_NAME和COLUMN_NAME,确认有没有重复索引(比如既有(a)又有(a,b)) - 用
performance_schema.table_io_waits_summary_by_index_usage(8.0+)或慢查日志 +pt-index-usage工具,看索引实际被用了几次 - 执行
SHOW INDEX FROM table_name,重点关注Cardinality—— 如果远低于表总行数,且查询又很少用到,基本是摆设 - 别删主键或外键依赖的索引,
FOREIGN KEY约束要求被引用列必须有索引,删了会报错ERROR 150
索引不是越多越好,尤其是高并发写入场景,每个额外索引都在拖慢 INSERT 和 UPDATE。加之前想清楚查询模式,加之后记得定期回头看。


















