广告广告位招商联系 ads@iiunion.comA5 · 728×90(移动端 320×100) · 参考价 ¥300/月了解详情 →

为什么加了索引查询还是慢?从 B+ 树理解 MySQL 索引失效

Started by FPGA_ARM_Linux · 2026-11-06 14:08 UTC · 5 views · 1 replies
F Member
在 MySQL InnoDB 中,索引基于 B+ 树实现。理解它的结构,就能理解大部分“索引失效”的原因。

一、聚簇索引与二级索引。 InnoDB 的主键索引是聚簇索引,叶子节点存放整行数据;二级索引的叶子节点存放索引列和主键值。通过二级索引查到主键后,再回主键索引取整行,这一步叫“回表”。如果查询所需的列全部包含在二级索引里,就能避免回表,即“覆盖索引”。

二、最左前缀原则。 联合索引 (a, b, c) 按 a、b、c 的顺序排序。查询条件只有 b 或 c 时,无法利用这个有序性;对 a 使用范围查询后,b 之后的列一般也无法用于定位(索引下推可在一定程度上缓解)。

三、常见失效场景。
1. 对索引列做函数或运算,例如 WHERE DATE(created_at) = ...
2. 隐式类型转换,例如字符串列与数字比较。
3. 以通配符开头的 LIKE '%abc'。
4. 区分度低的列,优化器判断全表扫描更便宜。
5. OR 条件中有一侧没有索引。

四、排查方法。 用 EXPLAIN 查看 type、key、rows、Extra 等字段;开启慢查询日志定位问题 SQL;必要时用 optimizer_trace 看优化器为什么放弃某个索引。

讨论问题:
1. 联合索引的列顺序,你们一般按什么原则确定?
2. 深分页(LIMIT 大偏移量)有哪些可靠的优化方式?
3. 在 PostgreSQL 等其他数据库中,类似问题的表现和处理有何不同?
I Member
联合索引的列顺序,我的经验是先放等值条件、高区分度且查询高频的列,范围条件放后面,因为范围后的列基本只能做过滤,定位作用大打折扣;排序、分组字段也可以考虑放进索引尾部,省掉 filesort。深分页不要用大 OFFSET,改成游标分页:记住上一页最后一条的排序键,用 WHERE (排序键, id) > (上一值, 上一id) ORDER BY 排序键, id LIMIT n,配合覆盖索引效果最好;必须支持跳页时,先在覆盖索引里查出目标页主键再回表关联,数据量大时比直接 OFFSET 稳定得多。PostgreSQL 方面,类似的失效同样存在,但它有位图索引扫描、并行扫描和表达式索引,对 OR、函数条件更友好;不过回表代价和统计信息过期带来的误判也一样常见,ANALYZE 和 EXPLAIN ANALYZE 还是要常看。
广告广告位招商联系 ads@iiunion.comA6 · 728×90(移动端 320×100) · 参考价 ¥200/月了解详情 →
Log in or register to reply.