索引加速SELECT查询的根本原因是改变数据访问方式:无索引需全表扫描,有合适索引可直接定位目标行或范围,依赖B+树有序结构和最左前缀匹配规则。

索引为什么能加速 SELECT 查询
根本原因不是“索引快”,而是它改变了数据访问方式:没有索引时,MySQL 必须全表扫描(type: ALL),逐行比对;有合适索引时,可直接定位到目标行或范围,跳过大量无关数据。这依赖 B+ 树的有序结构和最左前缀匹配规则。
注意:索引只在查询条件中实际用到的列上生效。比如建了 (a, b, c) 联合索引,但查询写的是 WHERE b = 1,该索引大概率不会被使用——因为不满足最左前缀。
- 用
EXPLAIN看key和possible_keys是否命中索引 -
type字段是关键:const/ref/range表示走了索引,ALL或index往往意味着慢 - 索引列参与计算(如
WHERE YEAR(create_time) = 2023)或加了函数/表达式,会导致索引失效
哪些字段适合建索引
不是“查得频繁就加索引”,而是看是否具备高选择性、是否出现在 WHERE / JOIN / ORDER BY / GROUP BY 子句中,并且未被函数包裹。
- 主键自动建聚簇索引,无需额外操作
- 外键字段建议建索引,避免关联查询时锁表或全表扫描
- 经常用于排序的字段(如
ORDER BY created_at DESC),可考虑联合索引覆盖排序需求 - 区分度低的字段(如
gender只有男/女)单独建索引意义不大,但作为联合索引的后缀可能有效 - 大文本字段(
TEXT、VARCHAR(2000))不能直接建完整索引,需指定前缀长度,如INDEX idx_title (title(100))
ALTER TABLE ... ADD INDEX 的实际影响
在线加索引在 MySQL 5.6+ 支持 ALGORITHM=INPLACE,但仍会阻塞写操作(INSERT/UPDATE/DELETE),且占用磁盘空间翻倍(临时索引文件 + 原表)。生产环境务必避开高峰期执行。
- 加索引前先用
SHOW CREATE TABLE确认当前索引结构,避免重复创建 - 联合索引顺序很重要:
(status, user_id)和(user_id, status)是两个完全不同的索引,适用场景不同 - 删除无用索引用
DROP INDEX idx_name ON table_name,减少写入开销和维护成本 - 监控
information_schema.STATISTICS或使用sys.schema_unused_indexes(MySQL 8.0+)识别长期未命中的索引
为什么加了索引反而变慢
常见错觉:只要建了索引,查询一定快。实际上,优化器可能因统计信息过期、索引选择率误判或查询条件太宽泛而放弃使用索引,转为全表扫描。更隐蔽的问题是索引本身成了负担。
- 小表(比如几千行)加索引收益极小,甚至因多一次B+树查找而更慢
- 写多读少的表,每个
INSERT都要更新多个索引,拖慢整体吞吐 -
LIKE '%abc'这类前导通配符无法使用索引,但LIKE 'abc%'可以 -
隐式类型转换导致索引失效,例如字段是
VARCHAR,却用数字查询:WHERE mobile = 13800138000(应加引号)
真正有效的索引优化,永远从 EXPLAIN 结果出发,结合真实查询模式和数据分布来判断,而不是凭经验堆砌索引。











