<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>B+Tree on Leanku 的博客</title><link>https://www.leanku.com/tags/b+tree/</link><description>Recent content in B+Tree on Leanku 的博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 12 Mar 2023 22:46:01 +0800</lastBuildDate><atom:link href="https://www.leanku.com/tags/b+tree/index.xml" rel="self" type="application/rss+xml"/><item><title>B+Tree</title><link>https://www.leanku.com/post/computerscience/b-tree/</link><pubDate>Sun, 12 Mar 2023 22:46:01 +0800</pubDate><guid>https://www.leanku.com/post/computerscience/b-tree/</guid><description>&lt;h1 id="btree"&gt;B+Tree&lt;/h1&gt;&#10;&lt;p&gt;B+Tree 是一种平衡多路搜索树，广泛应用于数据库和文件系统等领域，其核心优势在于优化磁盘存储效率和查询性能.&lt;/p&gt;&#10;&lt;p&gt;MySQL的InnoDB存储引擎使用的索引结构就是 B+树，它是B树的一个重要变种。&lt;/p&gt;&#10;&lt;h2 id="1-从b树到b树"&gt;1. 从B树到B+树&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;B树&lt;/strong&gt;：一种自平衡的、多路的搜索树。它允许每个节点有多个子节点（多于两个，所以不是二叉树）。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;B+树&lt;/strong&gt;：在B树基础上优化而来的数据结构，是现代数据库系统中&lt;strong&gt;事实上的标准索引结构&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;MySQL的InnoDB使用的正是 &lt;strong&gt;B+树&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;h2 id="2-为什么数据库需要b树"&gt;2. 为什么数据库需要B+树？&lt;/h2&gt;&#10;&lt;p&gt;要理解B+树，必须先理解它的设计目标。数据库的数据存储在磁盘上，磁盘I/O（读写磁盘）的速度比内存访问慢几个数量级。因此，数据库索引的核心目标是：最大限度地减少磁盘I/O次数。&lt;/p&gt;&#10;&lt;p&gt;B+树通过以下方式完美地实现了这一目标：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;矮胖&lt;/strong&gt;：与“瘦高”的二叉树相比，B+树每个节点可以存储非常多的键，这使得树的层级非常少（通常只有3-4层），从而保证在亿万级数据量下，查找任何一条记录最多只需要3-4次磁盘I/O。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;顺序访问友好&lt;/strong&gt;：B+树非常适合磁盘的预读特性，能够高效地进行范围查询。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="3-b树的详细结构"&gt;3. B+树的详细结构&lt;/h2&gt;&#10;&lt;p&gt;它由两种类型的节点组成：内部节点 和 叶子节点。&lt;/p&gt;&#10;&lt;h4 id="内部节点非叶子节点"&gt;&lt;strong&gt;内部节点（非叶子节点）&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;：仅充当&lt;strong&gt;导航目录&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;存储内容&lt;/strong&gt;：只存储&lt;strong&gt;键值&lt;/strong&gt;（索引列的值）和指向子节点的&lt;strong&gt;指针&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;不存储&lt;/strong&gt;：实际行的数据。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h4 id="叶子节点"&gt;&lt;strong&gt;叶子节点&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;作用&lt;/strong&gt;：存储&lt;strong&gt;实际的数据&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;存储内容&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;在 &lt;strong&gt;主键索引（聚簇索引）&lt;/strong&gt; 中：叶子节点存储的就是&lt;strong&gt;完整的行数据&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;在 &lt;strong&gt;辅助索引（二级索引）&lt;/strong&gt; 中：叶子节点存储的是该索引的&lt;strong&gt;键值&lt;/strong&gt;和对应的&lt;strong&gt;主键值&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;strong&gt;关键特性&lt;/strong&gt;：所有叶子节点通过指针相互连接，形成了一个&lt;strong&gt;有序的双向链表&lt;/strong&gt;。这是B+树与B树的一个核心区别。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="4-b树的核心特性与优势对比b树"&gt;4. B+树的核心特性与优势（对比B树）&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;特性&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;B树&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;B+树&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;B+树的优势&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;数据存储位置&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;内部节点和叶子节点都存储数据。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;只有叶子节点存储数据，内部节点仅为索引。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;更“矮胖”的树。因为内部节点不存数据，所以一个节点能容纳的键更多，扇出（子节点数）更大，树高更低，I/O次数更少。&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;叶子节点链接&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;叶子节点之间没有链接。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;叶子节点通过双向链表连接。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;无敌的范围查询。要查询age BETWEEN 20 AND 30的所有记录，B+树只需找到20，然后顺着链表遍历即可。B树则需要不断地在树的中上层和下层之间来回跳跃，性能极差。&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;扫描和全表遍历&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;需要对整棵树进行复杂的中序遍历。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;只需遍历底层的链表即可获得所有数据，非常高效。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;对数据仓库、聚合查询等场景非常友好。&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;查询稳定性&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;由于数据可能在内部节点找到，查询时间不稳定。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;任何查询都必须走到叶子节点，查询时间非常稳定。&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;保证了可预测的性能。&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="5-在mysql中的具体体现聚簇索引"&gt;5. 在MySQL中的具体体现：聚簇索引&lt;/h2&gt;&#10;&lt;p&gt;在MySQL InnoDB中，主键索引就是一颗B+树，并且这棵B+树的叶子节点直接存储了完整的行数据。这种索引组织表的方式被称为“聚簇索引”。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;表数据文件本身就是按B+树结构组织的一个索引文件。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;如果你没有定义主键，InnoDB会选择一个唯一的非空索引代替，如果没有这样的索引，它会隐式地定义一个主键。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;辅助索引（二级索引）&lt;/strong&gt; 也是一颗B+树，但它的叶子节点存储的是&lt;strong&gt;该索引列的值&lt;/strong&gt;和&lt;strong&gt;对应记录的主键值&lt;/strong&gt;。当通过二级索引查找数据时，需要先找到主键，再回到主键索引（聚簇索引）中查找完整数据，这个过程称为“&lt;strong&gt;回表&lt;/strong&gt;”。&lt;/p&gt;</description></item></channel></rss>