索引为什么能加速 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结果出发,结合真实查询模式和数据分布来判断,而不是凭经验堆砌索引。
