索引不是字段旁边的一个“加速开关”,而是一种数据组织方式。它把数据按某个键排成适合查找和范围扫描的结构,同时把维护成本转移到写入、页分裂、缓存和回表上。

MySQL 大规模使用 B+ 树,不是因为哈希表不好,而是因为数据库面对的是范围查询、磁盘页、顺序扫描和持续更新。理解索引模型,要先看它解决了什么访问问题,又把成本放到了哪里。

先把机制边界说清楚

索引本质上是一种数据组织方式。它不是附着在表外面的神奇目录,而是把数据按照某个键重新排成一套适合查找、范围扫描和维护的结构。数据库面对的不是几十个内存对象,而是几百万、几千万页数据,真正昂贵的是随机磁盘 IO 和缓存未命中。

整体路径

索引模型:B+ 树为什么适合数据库

上面这张图先看粗线条:宏观上看,索引模型是在“等值查找、范围扫描、写入维护、页级缓存”之间做平衡。哈希表的等值查询很快,但范围查询几乎无从谈起;有序数组范围扫描优秀,但插入移动成本太高;二叉搜索树如果每个节点都落到磁盘页上,树高和随机 IO 会失控。B+ 树把多路分叉、页大小和叶子链表结合起来,让一次点查通常只需要访问少量页,让范围查询可以从起点沿叶子节点顺序扫。

底层流程

索引模型:B+ 树为什么适合数据库:执行路径

底层拆解先看数据结构。「索引模型」至少涉及下面几类结构:

  • 页:InnoDB 以页为基本读写单位,索引节点也落在页里。
  • 非叶子节点:保存键值和子页指针,尽量少放数据以提高扇出。
  • 叶子节点:保存有序键值和实际数据或主键引用,并通过链表支持范围扫描。
  • 根页与中间页:常驻热点概率高,降低树高带来的随机 IO。

再看完整执行流程:

  1. 根据查询条件计算要走的索引范围。
  2. 从根页开始比较键值,逐层定位到目标叶子页。
  3. 点查在叶子页内定位记录,范围查找到起点后沿叶子链表向后扫描。
  4. 如果查询列不在当前索引里,再进入回表流程。

取舍与边界

版本差异上,MySQL 5.7 和 8.0 都以 InnoDB B+ 树为核心索引结构。8.0 在降序索引、隐藏索引、直方图统计等方面补足了优化器能力,但底层“页 + B+ 树 + 聚簇组织”的基本模型没有变。

B+ 树并不是没有代价。随机主键会导致页分裂和写放大;过多二级索引会让每次写入维护多棵树;低区分度索引会产生大量回表;大范围扫描即使走索引,也可能比顺序扫全表更慢。

典型问题:用机制化例子排查

索引设计的典型问题不是“有没有索引”,而是这条索引能不能同时服务过滤、排序、范围扫描和回表控制。只给单个字段加索引,常常只是把问题往后推。

可以落到这些动作:

  • 索引设计先看访问路径,不要按字段清单机械建索引。
  • 高频范围查询优先考虑联合索引,让过滤和排序共享同一棵树。
  • 低区分度字段单独建索引要谨慎,除非能与其他字段组合缩小范围。
  • 写密集表控制二级索引数量,定期用慢查询和索引使用情况清理无效索引。

收束:索引是访问路径设计

索引设计不是给字段贴加速标签,而是在读路径和写成本之间做交换。能不能服务过滤、排序、范围扫描和回表控制,比“有没有索引”更重要。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。

我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。

如果你想继续跟完这套「图解 MySQL」,欢迎关注公众号 「十三Tech」。后续会继续按机制、图解和实战排查这条线更新。

十三Tech公众号二维码