索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。可以将数据库索引和书的目录进行类比,通过书的目录我们可以快速查找到章节位置,如果没有目录就只能一页页翻书查找了。
索引数据结构
可以用于提升查询效率的索引结构很多,常见的有B树索引、哈希索引和B+树索引。接下来我们会对这些索引一一进行介绍,并说明InnoDB为什么采用B+树作为索引。
磁盘IO
文件是存储在硬盘上面的。当下硬盘的读取速度十分有限,所以在进行查询定位某个数据的时候,应该尽可能地减少磁盘I/O次数。
磁盘预读
由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分之一,因此为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。程序运行期间所需要的数据通常比较集中。
局部性原理:CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。
预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页的大小通常为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。
合理利用磁盘预读
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数。换句话说,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数。
如果我们能合理使用磁盘预读的特性,使每次磁盘IO读到的页中的数据都是有用的,就可以大大提升数据的查询效率。
B树索引
B树可以看作是对二叉查找树的一种扩展,B树允许每个节点有M-1个子节点,B树有以下特点:
- 根节点至少有两个子节点;
- 每个节点包含M-1条数据,节点中的数据安装索引递增顺序排序;
- 节点中有最多有M个指针指向下一层节点,这些指针位于节点的多个数据之间,下一层节点的所有数据值大于指针左侧的数据,小于指针右侧的数据;
- 每个节点至少包含M/2条数据;
接下来我们用下表示例的用户数据来构建B树,如表所示,用户数据包含姓名、性别、年龄三个字段,我们把用户年龄作为数据库主键(假设年龄具有唯一性),那么构建出来的B树的结构如下图所示。
姓名 | 陈尔 | 张散 | 李思 | 王舞 | 赵流 | 孙期 | 周跋 | 吴酒 | 郑史 |
性别 | 男 | 男 | 女 | 女 | 男 | 男 | 男 | 女 | 男 |
年龄 | 5 | 10 | 20 | 28 | 35 | 56 | 25 | 80 | 90 |
![B树索引]