当前位置: 首页 > news >正文

MySQL 索引底层 B+ 树原理

聊 MySQL 索引不讲 B 树那就是在耍流氓。大家好我是乱码字符。今天咱们深入聊聊 MySQL 索引的底层数据结构——B 树。这篇文章能让你彻底搞明白为什么有时候明明加了索引查询却还是慢成狗。先说说为什么要用树结构想象一下如果数据存在数组里你要查一条id 10086的记录最坏情况得遍历整个数组时间复杂度 O(n)。数据少还行一旦数据量级到了千万、亿这个级别查询效率就炸了。所以我们需要一种查找效率高的数据结构。哈希表那玩意儿只能做等值查询范围查询比如查id 100就歇菜了。树结构天然支持高效的范围查询这就是 MySQL 选择 B 树的主要原因。B 树长啥样先上一张经典的 B 树结构图建议收藏[50 | 100] / | \ [20|30] [60|80] [120|150] / | \ / | \ / | \ ... ... ... ... ... ... ... 简单说B 树是一种**多叉平衡树**有多牛呢看几个关键特性 1. **只有叶子节点存数据**——非叶子节点只存索引键值叶子节点才是真正存数据的地方 2. 2. **叶子节点用指针串起来**——这也就是为什么 B 树特别适合范围查询 3. 3. **绝对平衡**——所有叶子节点都在同一层查询性能极其稳定 ## B 树 vs B 树有啥区别 面试官最喜欢问这个记住了 | 特性 | B 树 | B 树 | |------|------|-------| | 数据存储 | 非叶子节点也存数据 | 只有叶子节点存数据 | | 范围查询 | 需要遍历整棵树 | 叶子节点用指针串起直接遍历 | | 查询稳定性 | 最差 O(log n) | 稳定 O(log n)因为只有叶子节点存数据 | | IO 次数 | 更多非叶子节点也读磁盘 | 更少矮胖结构 | ## MySQL 中 B 树是怎么存的 在 InnoDB 存储引擎中**主键索引就是一颗 B 树**。 假设我们有一张用户表 sql CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, name varchar(50) DEFAULT NULL, age int DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB; 当你执行 SELECT * FROM user WHERE id 10 时MySQL 干的事儿是这样的 1. 先从**主键索引树**的根节点开始 2. 2. 根节点里存了页目录根据 id10 找到对应的指针 3. 3. 往下走最终定位到叶子节点 4. 4. 叶子节点里存的才是完整的行数据 整个过程只需要 **3-4 次磁盘 IO**取决于树的高度非常快。 ### 等等主键索引叶子节点存啥 InnoDB 的主键索引叶子节点存的是**完整的行数据**。这就是所谓的**聚簇索引**Clustered Index。 那如果我建的是普通索引非主键索引呢 sql CREATE INDEX idx_age ON user(age);普通索引的叶子节点存的不是完整数据而是主键值 索引列的值。查的时候先通过普通索引找到主键再去主键索引树查一遍——这叫回表。一个页能存多少数据InnoDB 默认页大小是16KB。假设主键是 bigint8字节加上一些指针开销一行数据大概占 1KB那么一个页能存16条左右的数据。一个 B 树根节点能存 1000 多条索引每个索引往下能分出 1000 多个子节点……算下来高度为 2 的 B 树1000 × 16 1.6万条数据高度为 3 的 B 树1000 × 1000 × 16 1600万条数据高度为 4 的 B 树能存16亿条数据所以绝大多数情况下B 树的高度都是2-3 层查询只需要 2-4 次磁盘 IO。什么时候索引会失效既然索引这么好使为啥有时候加了索引还是慢常见原因1. 索引列用了函数或运算-- 索引失效SELECT*FROMuserWHEREYEAR(created_at)2024;-- 应该改成范围查询SELECT*FROMuserWHEREcreated_at2024-01-01ANDcreated_at2025-01-01;2. 字符串不加引号-- 索引失效隐式类型转换SELECT*FROMuserWHEREphone13800138000;-- 正确写法SELECT*FROMuserWHEREphone13800138000;3. 最左前缀原则-- 建立了索引 (name, age, city)-- 可以用索引的情况WHEREnameTomWHEREnameTomANDage25-- 不能用索引的情况WHEREage25WHEREcityBeijing4. 模糊查询%开头的最左前缀原则-- 索引失效SELECT*FROMuserWHEREnameLIKE%om;-- 可以用索引SELECT*FROMuserWHEREnameLIKETom%;实战看看你的索引长啥样用EXPLAIN看看查询有没有走索引EXPLAINSELECT*FROMuserWHEREid10;输出里的type列很重要type 值含义const常量查询用了主键索引或唯一索引ref用了普通索引查找多条range范围查询index全索引扫描ALL全表扫描最糟糕总结一下B 树是 MySQL 索引的底层结构只有叶子节点存数据用指针串起来适合范围查询主键索引是聚簇索引叶子节点存完整行数据普通索引是非聚簇索引叶子节点存主键值需要回表注意索引失效的几种情况尤其是函数、隐式转换、最左前缀用 EXPLAIN 分析查询确保走了索引而不是全表扫描好了B 树原理就聊到这儿。如果还想看更多 MySQL 硬核原理点个关注咱们下期见。往期热门[MySQL 事务隔离级别详解][MySQL 执行计划 EXPLAIN 详解][MySQL 慢查询优化实战]
http://www.rkmt.cn/news/1302517.html

相关文章:

  • 3D打印定制外壳:为Adafruit HalloWing打造可穿戴电子装饰
  • OBS鼠标位置追踪插件:提升直播教学与游戏演示的视觉指引
  • 从零构建高效个人技术工具箱:Hub仓库的设计、实践与维护指南
  • openclaw-memory:为LLM应用构建高效记忆系统的工程实践
  • Neovim集成Goose数据库迁移工具:提升开发效率的现代化插件方案
  • 2026年期刊投稿论文降AI攻略:学术期刊投稿论文AIGC超标4.8元快速达标完整方案
  • 2026年商科案例分析论文降AI攻略:MBA案例分析论文AIGC超标免费4.8元知网达标完整方案
  • Godot强化学习实战:用godot_rl_agents训练游戏AI
  • 期权交易基础框架:模块化设计与Python实现指南
  • GitClaw:基于Go的轻量级Git钩子服务器与集中式权限管理方案
  • Python自动化工具:YouTube播放列表批量导出为结构化文本
  • 3步极速获取百度网盘提取码:开源神器baidupankey的智能解密指南
  • 六轴串联机械臂路径规划【附程序】
  • 程序员超能力:代码技能树全解析
  • PowerInfer:基于热点神经元预测的LLM高性能推理引擎部署指南
  • 构建高可用AI模型代理服务:统一接口、智能路由与生产级部署
  • Arm架构Iris事件流机制与断点调试技术详解
  • 毕业论文党福音:手把手教你用Endnote X9搞定参考文献,告别手动编号噩梦
  • Godot游戏集成Discord状态:RPC插件原理与实战指南
  • Go语言缓存雪崩:防止缓存失效
  • Linux防火墙规则检查与放通实践
  • Rulebook-AI:用规则引擎为AI智能体构建可控决策框架
  • 三维重建实时映射技术在智慧水利中的核心应用
  • 去除豆包视频水印(最稳定小程序)福气满满去水印小程序 - 政企云文档
  • Arm CoreLink PCK-600电源管理架构与寄存器编程详解
  • Bifrost:轻量高效的实时数据同步平台架构与实战
  • 深入解析go-containerregistry:无守护进程的容器镜像操作利器
  • 基于电容触摸与NeoPixel的交互式音乐城堡制作全解析
  • 如何在 CI/CD 流水线中自动根据分支名部署环境?
  • ARM RealView Debugger调试工具入门与实践指南