MySQL索引优化从B+Tree原理到慢查询分析

AI5天前发布 beixibaobao
7 0 0

一、B+Tree为什么适合数据库索引

MySQL InnoDB 默认使用 B+Tree 索引。它的特点是多路平衡、层高低、叶子节点有序并通过链表相连。相比二叉树,B+Tree 一次磁盘页能放更多 key,查找通常只需要少量随机 IO;相比哈希索引,它天然支持范围查询、排序和最左前缀匹配。

索引能力 B+Tree表现 典型场景
等值查询 很好 id、订单号
范围查询 很好 时间区间
排序 可利用有序性 ORDER BY
模糊前缀 可部分利用 name LIKE ‘ab%’
后缀模糊 难利用 LIKE ‘%ab’

二、联合索引与最左前缀

联合索引不是多个单列索引的简单叠加。(tenant_id, status, created_at) 的顺序决定了查询能走到哪里。等值条件通常放前面,范围字段放后面,排序字段要结合查询模式设计。

CREATE INDEX idx_order_query
ON orders (tenant_id, status, created_at);
EXPLAIN SELECT id, amount
FROM orders
WHERE tenant_id = 1001
  AND status = 'PAID'
  AND created_at >= '2026-07-01'
ORDER BY created_at DESC
LIMIT 20;

如果查询没有 tenant_id,这个索引很难高效使用。很多慢查询来自“看起来有索引”,但实际条件不符合最左前缀。设计索引前应先收集高频 SQL,而不是按字段名机械建索引。

三、用EXPLAIN识别问题

EXPLAIN 是慢查询分析的入口。重点看 typekeyrowsExtratype 从好到差大致是 constrefrangeindexALL。如果 rows 很大且 Extra 出现 Using filesortUsing temporary,就要检查过滤条件和排序是否能被同一个索引支持。

EXPLAIN FORMAT=TREE
SELECT *
FROM orders
WHERE DATE(created_at) = '2026-07-08';

上面这种写法会对列使用函数,可能导致索引失效。应改成范围条件:

WHERE created_at >= '2026-07-08 00:00:00'
  AND created_at <  '2026-07-09 00:00:00'

同理,隐式类型转换、前置百分号模糊查询、低选择性字段单独建索引,都可能让优化器放弃索引。

四、慢查询治理要闭环

打开慢查询日志后,不要只盯单条 SQL 的耗时,还要看频率和扫描行数。一个 200 毫秒但每分钟执行上万次的查询,影响可能比偶发 3 秒查询更大。

SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 0.5;

生产环境应通过平台化方式采集慢日志,按指纹聚合,再结合业务上下文处理。索引不是越多越好,写入、更新和磁盘占用都会随索引增加而上升。一次可靠的优化应包含:确认慢 SQL、分析执行计划、设计或调整索引、压测验证、上线观察,并清理不再使用的冗余索引。

还要关注数据分布变化。一个索引在数据量小时表现很好,半年后可能因为热点租户、状态字段倾斜或历史数据堆积而退化。可以定期查看表统计信息、索引基数和慢查询趋势。对于归档类数据,冷热分离或分区表有时比继续堆索引更有效。索引优化不是一次性动作,而是随业务增长持续校准访问路径。

上线新索引也要评估写入成本。大表加索引可能耗时较长,应选择低峰期,必要时使用在线变更工具,并提前准备回退方案。


📌 本文是《数据库性能实战》系列,持续更新,关注不迷路。
👉 下一篇:《MySQL事务隔离级别与MVCC机制解析》,讲索引之外事务可见性与锁范围如何影响并发。
💬 你在实际项目里遇到过索引存在却没被优化器选中的问题吗?评论区聊聊。
(觉得有用点个赞+收藏,方便回头查阅)
🔧 相关可运行源码/资料已整理成资源包,可在我主页的资源里自取。

© 版权声明

相关文章