一、索引为什么快
MySQL InnoDB 的索引是 B+ 树结构。没有索引时查询要全表扫描(逐行比对),有了索引就像查字典——通过树形结构二分定位,查询次数从 O(n) 降到 O(log n)。
但索引不是越多越好:每次写操作都要同步维护索引树,索引太多会拖慢插入和更新。
二、怎么建索引
1 | -- 单列索引 |
建索引的优先级:
- WHERE 条件字段(过滤最狠的先放)
- JOIN 关联字段
- ORDER BY / GROUP BY 字段
- 区分度高的字段(性别这种只有两种值的,索引意义不大)
三、EXPLAIN:看执行计划
1 | EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid'; |
返回的关键列:
| 列 | 含义 | 重点 |
|---|---|---|
type |
访问类型 | 从好到差:system > const > eq_ref > ref > range > index > ALL,出现 ALL(全表扫描)要警惕 |
key |
实际用到的索引 | NULL 说明没走索引 |
rows |
预估扫描行数 | 越小越好,和实际行数差距大说明统计信息过期 |
Extra |
额外信息 | Using index(覆盖索引,好);Using filesort(文件排序,要优化);Using temporary(临时表,要优化) |
优化信号:
1 | -- 慢的:type=ALL,全表扫描 |
四、最左前缀原则(联合索引核心)
联合索引 (user_id, status, created_at) 相当于建了三个索引:(user_id)、(user_id, status)、(user_id, status, created_at)。
能用上的情况:
1 | WHERE user_id = 100 -- ✅ 用到第一列 |
用不上的情况:
1 | WHERE status = 'paid' -- ❌ 跳过了第一列,索引失效 |
经验:查询条件里最常用、区分度最高的字段放联合索引最前面。
五、覆盖索引:查询只读索引
如果查询的所有字段都在索引里,MySQL 不用回表查数据行,这就是 Using index:
1 | -- 建了联合索引 (user_id, status),下面的查询只读索引即可 |
覆盖索引是超高并发场景的核心优化手段,比回表快一个数量级。
六、常见索引失效场景
1 | -- 1. 对索引列做运算或函数 |
七、慢查询日志
1 | -- 查看慢查询设置 |
拿到慢 SQL 后的标准流程:
EXPLAIN看执行计划;- 确认有没有走索引、扫描行数多少;
- 按”最左前缀 + 覆盖索引 + 去掉函数/隐式转换”三板斧改 SQL 或建索引;
- 改完复测,对比
rows和执行时间。
常见坑
- 索引建了但不走:大概率是隐式转换、函数包裹、或统计信息过旧(
ANALYZE TABLE); - 联合索引顺序错了:最常用的字段没放前面,导致索引部分失效;
- 过度索引:一张表 10+ 个索引,写放大严重,用
SHOW INDEX FROM 表名定期清理冗余; - 只信 rows 不信实测:rows 是估算值,最终以
EXPLAIN ANALYZE(MySQL 8.0.18+)实测为准。
总结
索引优化的核心流程:先 EXPLAIN 看现状 → 按最左前缀设计联合索引 → 用覆盖索引避免回表 → 排查函数/类型转换导致的失效 → 用慢查询日志定位真问题。把这几招练熟,90% 的慢查询都能自己解决。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 JCAlways!
评论
