[{"data":1,"prerenderedAt":66},["ShallowReactive",2],{"article-147":3},{"code":4,"msg":5,"data":6,"count":14},200,"查询成功",{"id":7,"title":8,"keywords":9,"description":10,"category_id":11,"content":12,"body_html":13,"thumb_up":14,"clicks":15,"sort":14,"remark":13,"status":16,"is_open":16,"is_deleted":14,"is_top":16,"is_recommend":16,"create_time":17,"update_time":18,"image_id":19,"url":13,"member_id":14,"cate_name":20,"prev":21,"next":24,"tags":27,"words":37,"read_time":38,"comments":14,"cover":39,"relevant":40},147,"数据库索引的定海神针：B+ 树凭什么这么能打？","B+树, 数据库索引, 磁盘I\u002FO, 范围查询, B树对比","为什么 MySQL、PostgreSQL 等关系型数据库的底层索引，清一色选择了 B+ 树？这篇文章从磁盘读写特性、查询稳定性、范围扫描和存储模型等角度，把 B+ 树相对 B 树的那些碾压级优势拆开了聊，看清它在工程上的“独一份”价值。",6,"![](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260529\u002F3a80826f89b2ef414562dacc0f667b85.png)\n如果你去看数据库的底层实现，不论 MySQL 的 InnoDB、PostgreSQL，还是商用的 Oracle，一提到索引，几乎全是 B+ 树的天下。很多人念书的时候都学过 B 树，难免会嘀咕：B+ 树不就是叶子节点多了一串链表吗，真就非它不可？放到工程里，差别比想象中大得多，而这差别的根源，几乎都来自一个慢得让人抓狂的东西——磁盘。\n![](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260529\u002Ffab78aed458cd21743b0ef16074760d7.png)\n\n\n数据库的数据老老实实躺在硬盘上，磁盘读写是毫秒级的，内存访问是纳秒级的，差了好几个数量级。索引结构好不好，关键就看谁能让磁盘少动弹两次。B+ 树的第一个优点就埋在这里：**内部节点只存索引键，不存实际数据或数据地址**，像一本极薄极清晰的目录。一个 16KB 的磁盘页，能塞进的键数远比 B 树多，**扇出**（每个节点能指出去的分支数）被撑得很大。同样体量的数据，B+ 树的高度往往比 B 树矮一层甚至更多。树矮一层，查找就能少一次磁盘 I\u002FO；在海量数据下，每少一次 I\u002FO 都是白花花的性能。而且，因为内部节点足够瘦，数据库能把高层内部节点全缓存在内存里，根到叶的路径更短、命中率更高，这点对高并发场景尤其实在。\n\n再往深一层想，B 树有个“小聪明”：数据允许挂在内部节点上，运气好查个键直接在中间就拿到，不用每次都走到叶子。乍一听像是优势，但这点小便宜对数据库反而添乱。B+ 树索性做得更绝——**把所有数据都压到叶子节点**，想找任何一个键，都必须乖乖从根爬到叶子。听着像多走了路，可恰恰让每一次查询的开销变得极其稳定，没有任何波动。查询优化器做代价估算、响应时间监控，都能吃准“每次都固定走到底”的规律。对线上系统来说，稳定的平均延迟比偶尔极快、偶尔极慢要重要得多。这种底层的可预测性，是 B+ 树送给数据库工程师的一颗定心丸。\n![](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260529\u002Fd0e6dd110b270fae03d13677aa3e03b4.png)\n\n不过，B+ 树真正的杀手锏，还是**范围查询和顺序扫描**。叶子节点被一条双向链表串在一起，所有数据天然按顺序排好。比如要找 `age BETWEEN 20 AND 30`，系统先定位到键值 20 的叶子，然后顺着链表一口气往后捋，一直捋到 30 收工——这完完全全是磁盘最喜欢的顺序读，速度逼近连续拷贝文件，预读机制也能放心大胆地把后续数据页提前拽进缓存。\n![](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260529\u002Fb021d4dbec0a63b028aea599d3f08c75.png)\n\n反过来看 B 树，范围查询只能靠中序遍历，在树上跳来跳去，每一步都大概率是一次随机 I\u002FO，数据量越大，这种差距越是天壤之别。日常 SQL 里的大于、小于、`ORDER BY`、`GROUP BY`、全表扫描，几乎处处都是“顺序流水”的场景，B+ 树这个设计简直就是为关系型数据库量身定做的。\n\n容易被忽略的，还有内部节点精简之后的**维护成本**。删除或更新一条记录，B+ 树往往只需要动叶子节点，内部节点最多微调一下键值就行；而 B 树若数据恰好卡在内部节点，调整起来麻烦得多。插入分裂时，B+ 树也只需操心叶子层链表的重接和父节点的键更新，整体实现的清晰度、并发控制的复杂度，都比 B 树友好。再加上内部节点小巧紧凑，内存里能放更多索引页，缓存命中率又拉高了一截，相当于又省了一笔磁盘 I\u002FO。\n![](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260529\u002F5b304efa41bcd45965833a0082909693.png)\n\n最后不得不提，B+ 树跟数据库的物理存储模型契合得天衣无缝。在 InnoDB 这样的聚簇索引里，叶子节点直接存放整行数据，索引即数据；非聚簇索引的叶子则存主键值，回表时再顺着主索引的 B+ 树去取。无论是覆盖索引直接扫叶子拿结果，还是利用叶子链表快速分页，那种“内部纯索引 + 叶子链数据”的结构，让存储引擎的代码既统一又高效。\n\n说回来，B+ 树放弃的，只是“偶尔在内部节点提前命中”的这点运气，换来的却是更矮的身材、完全可预测的查询延迟、对顺序扫描几乎偏执的优化，以及和磁盘特性极度匹配的结构。在高并发、海量数据的真实世界里，这些取舍让 B+ 树几乎找不到对手。翻翻数据库内核的书你就会发现，B+ 树从来不是偶然的选择，而是被磁盘、SQL 模式和工程权衡三方合力推上去的那个最佳解。",null,0,31,1,"2026-05-21 22:36:06","2026-05-29 11:15:53",127,"Mysql",{"id":22,"title":23},146,"MySQL 查询优化：如何减少恼人的“回表”",{"id":25,"title":26},148,"SQL 跑得慢？别慌，这里有份排查手册",[28,31,34],{"id":29,"name":30},135,"数据结构",{"id":32,"name":33},136,"数据库内核",{"id":35,"name":36},137,"存储引擎",1719,4,"https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Farticle\u002Fde\u002F36593248f37397d88a6a0d873ebaad.jpg",[41,46,51,56,61],{"id":42,"title":43,"create_time":44,"description":45},90,"Redis常见使用场景","2020-06-17 16:09:42","Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库，并提供多种语言的API。本篇文章，主要介绍利用PHP使用Redis，主要的应用场景。",{"id":47,"title":48,"create_time":49,"description":50},94,"客户端连接MySQL8提示 caching-sha2-password 问题","2020-10-19 10:55:26","在安装mysql8的时候如果选择了密码加密，之后用客户端连接比如navicate，会提示客户端连接caching-sha2-password,是由于客户端不支持这种插件，可以通过如下方式进行修改：",{"id":52,"title":53,"create_time":54,"description":55},87,"MySQL中InnoDB和MyISAM区别","2020-06-12 17:11:21","InnoDB具有事务，支持4个事务隔离级别，回滚，崩溃修复能力和多版本并发的事务安全，包括ACID.如果应用中需要执行大量的INSERT或UPDATE操作，则应该使用InnoDB,这样可以提高多用户并发操作的性能。MyISAM管理非事务表，提供高速存储和检索，以及全文搜索能力，如果应用中需要执行大量的SELECT查询，那么MyISAM是更好的选择。",{"id":57,"title":58,"create_time":59,"description":60},88,"MySQL实现循环插入千万级数据","2020-06-12 17:56:22","对于一些数据量较大的系统，数据库面临的问题除了查询效率低下，还有就是数据入库时间长。特别像报表系统，可能每天花费在数据导入上的时间就会长达几个小时之久。因此，优化数据库插入性能是很有意义的。",{"id":62,"title":63,"create_time":64,"description":65},86,"MySQL查询表结构命令","2020-06-09 11:30:00","###### MySQL查询表结构命令\n\n###### 1、查询表结构\n\n主要显示字段类型主键是否允许为空等\n\n```mysql\nDESC 表名;\n```\n\n结果显示\n\n| Field | Type         | Null | Key  | Default | Extra          |\n| :---- | ------------ | ---- | ---- | ------- | -------------- |\n| id    | int(11)      | NO   | P",1783431645741]