B树 是怎么存到硬盘上的？
纠正一下，innodb用的是B+树，不是B树。 B+树在Mysql里就是用来做索引结构的。看来题主是希望知道B+在磁盘里是长什么样子的。数据库里数据都是存在页的结构里的，我们来看下从数据页是怎么一步步变成B+树的，上面的疑问就都解决了。页的结构假设我们有这么一张user数据表。 其中id是唯一主键。这看起来的一行行数据，为了方便，我们后面就叫它们record吧。这张表看起来就跟个excel表格一样。excel的数据在硬盘上是一个xx.excel的文件。而上面user表数据，在硬盘上其实也是类似，放在了user.ibd文件下。含义是user表的innodb data文件，专业点，又叫表空间。虽然在数据表里，它们看起来是挨在一起的。但实际上在user.ibd里他们被分成很多小份的数据页，每份大小16k。类似于下面这样。 我们把视角聚焦一下，放到页上面。整个页16k，不大，但record这么多，一页肯定放不下，所以会分开放到很多页里。并且这16k，也不可能全用来放record对吧。因为record们被分成好多份，放到好多页里了，为了唯一标识具体是哪一页，那就需要引入页号（其实是一个表空间的地址偏移量）。同时为了把这些数据页给关联起来，于是引入了前后指针，用于指向前后的页。这些都被加到了页头里。页是需要读写的，16k说小也不小，写一半电源线被拔了也是有可能发生的，所以为了保证数据页的正确性，还引入了校验码。这个被加到了页尾。那剩下的空间，才是用来放我们的record的。而record如果行数特别多的话，进入到页内时挨个遍历，效率也不太行，所以为这些数据生成了一个页目录，具体实现细节不重要。只需要知道，它可以通过二分查找的方式将查找效率从O(n) 变成O(lgn)。 从页到索引如果想查一条record，我们可以把表空间里每一页都捞出来，再把里面的record捞出来挨个判断是不是我们要找的。行数量小的时候，这么操作也没啥问题。行数量大了，性能就慢了，于是为了加速搜索，我们可以在每个数据页里选出主键id最小的record，而且只需要它们的主键id和所在页的页号。组成新的record，放入到一个新生成的一个数据页中，这个新数据页跟之前的页结构没啥区别，而且大小还是16k。但为了跟之前的数据页进行区分。数据页里加入了页层级（page level）的信息，从0开始往上算。于是页与页之间就有了上下层级的概念，就像下面这样。 突然页跟页之间看起来就像是一棵倒过来的树了。也就是我们常说的B+树索引。最下面那一层，page level 为0，也就是所谓的叶子结点，其余都叫非叶子结点。上面展示的是两层的树，如果数据变多了，我们还可以再通过类似的方法，再往上构建一层。就成了三层的树。 那现在我们就可以通过这样一棵B+树加速查询。举个例子。比方说我们想要查找行数据5。会先从顶层页的record们入手。record里包含了主键id和页号（页地址）。看下图黄色的箭头，向左最小id是1，向右最小id是7。那id=5的数据如果存在，那必定在左边箭头。于是顺着的record的页地址就到了6号数据页里，再判断id=5>4，所以肯定在右边的数据页里，于是加载105号数据页。在数据页里找到id=5的数据行，完成查询。 另外需要注意的是，上面的页的页号并不是连续的，它们在磁盘里也不一定是挨在一起的。这个过程中查询了三个页，如果这三个页都在磁盘中（没有被提前加载到内存中），那么最多需要经历三次磁盘IO查询，它们才能被加载到内存中。 我们都知道，现在mysql的索引都是B+树，而有一种树，跟B+树很像，叫B树，也叫B-树。 它跟B+树最大的区别在于，B+树只在末级叶子结点处放数据表行数据，而B树则会在叶子和非叶子结点上都放。 于是，B树的结构就类似这样   注意B树的叶子节点加上非叶子节点才是完整的数据，因此范围查询时，或者遍历所有数据时，B树么有B+树那么方便。 为此，B+树比B树更适合成为mysql的索引。 答案节选自文章：为什么大家说mysql数据库单表最大两千万？依据是啥？ 