一、数据页的存储结构
磁盘数据文件虽然不是一个数据页对应一个文件,但是数据页之间是通过指针联系的,同时数据页内部的行数据也通过指针关联。
其实一个数据页在磁盘文件里就是一段有组织的数据。每个数据页都有两个指针,一个指向前一个数据页的物理地址,一个指向后一个数据页的物理地址
。数据页内部的每一行数据都会按照主键大小进行排序存储
,同时每一行数据都有一个指向下一行数据位置的指针。
此外,每个数据页都有一个页目录,里面保存的是每个记录的主键和所在的数据页地址的映射关系。如下图所示:
这样我们每次寻找一条数据的时候,只要先在页目录中通过二分查找找到这个数据的主键,然后得到这条数据所在数据页的地址,再去遍历那个数据页的所有行数据,找到主键相同的数据即可。
但是这样存在一个问题,就是如果我们不是通过主键而是通过其他字段查找,那就只能遍历所有数据页了。此外,如果数据量大了之后,这样查找性能肯定也有问题。针对这些问题,InnoDB其实使用索引(B+树)来解决的。
二、索引的结构
之前我们已经介绍过在行记录的的数据头部分有一个record_type
字段来表示当前记录的类型。0代表普通类型,1代表B+树的叶子节点类型,2代表是当前页的最小值数据,3代表是当前页的最大值数据。我们只要将每一页的最小主键值记录在一个主键目录中,然后查找的时候去比较一下,也可以找到对应的数据页。如下图:
假设我们要查询一条主键为3的记录,那么首先从主键目录中进行二分查找,发现3大于1但是小于4,所以主键为3的记录要么不存在,要么肯定在页号为2的数据页中,然后再去数据页2中遍历查找即可找到对应的记录。上面这个其实就是我们常说的主键索引。
那么这样设计的好处就是对于其他字段,我们同样可以建立一个对应的索引,查询的时候,直接通过那个字段对应的索引去查找记录即可。这样比前面提到的遍历所有数据页效率高很多。
三、B+树索引
上面说到主键索引目录里面存放的是每个数据页的最小值,那么如果数据量非常大之后,主键目录也要存放很多数据了。InnoDB实际上也是通过页的方式来存储主键目录的,称为索引页
。假设存在很多数据页,那么也就会存在很多索引页。如下图:
那么我们会发现索引多了之后又和之前数据页多了之后的问题一样,现在我们有一个主键,还是要从很多索引页里面查找。同样的思路再应用在索引页上,那就是为索引页再建一层索引。这样依次类推会建立出一个多层索引的结构。如下图:
这样即使数据量大了以后,我们也可以通过二分查找很快的找到数据所在的页。避免了遍历全表的耗时操作。仔细观察一下上面这个多层索引的结构,其实就是一个树状结构,并且是一个B+树的结构,所以也应对了我们的常识,InnoDB的索引是B+树结构。叶子节点其实是按照页的形式保存了真实的所有记录值,然后每个非叶子节点中保存了指向下一层级的记录最小值以及所在的页号(数据页或者索引页)。
同理,其他字段对应的二级索引也是这样的B+数结构,只不过二级索引的叶子节点里面保存的不是所有字段,而是主键值和二级索引的字段。通过一个字段查到主键值,再通过它的主键值查询主键所有就得到完整的记录。这个操作也成为“回表”。
THE END.