索引就是为了提高数据查询的效率,就像书的目录一样。
索引的常见模型
- 哈希表
- 只适用于等值查询的场景,对于范围查询只能走全表扫描。
- 有序数组
- 等值查询和范围查询场景中的性能都非常好。
- 插入性能太差。所以适合静态存储引擎,如2017年城市人口信息。
- 二叉树
- 查询复杂度是O(log(N))
- 二叉树的搜索效率是很高的,但是大多数的数据库存储不会用二叉树。因为索引不止存在内存中,还要写到磁盘上。想象一棵100万节点的平衡二叉树,树高20,一次查询可能需要访问20个数据块。从磁盘随机读一个数据块就需要10ms左右的寻址时间,那么20个数据块的访问时间就会达到200ms。
InnoDB的索引
在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。
在InnoDB中,索引使用B+树的索引模式。B+ 树能够很好地配合磁盘的读写特性,减少单次查询的磁盘访问次数。
左边是主键索引,右边是普通索引。主键索引的叶子节点存的是整行数据,普通索引的叶子节点存的是主键的值。
- 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
- 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。
也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。
索引维护
B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护。以上面这个图为例,如果插入新的行 ID 值为 700,则只需要在 R5 的记录后面插入一个新记录。如果新插入的 ID 值为 400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。
而更糟的情况是,如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。
所以使用自增主键的重要性就体现在这里了。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。
显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。
- 适合用业务字段直接做主键的场景
- 只有一个索引
- 该索引为唯一索引
总结
- InnoDB使用B+树作为索引模型。因为B+ 树能够很好地配合磁盘的读写特性,减少单次查询的磁盘访问次数。
- InnoDB是主键索引组织表
- 推荐使用自增主键