04 | 深入浅出索引(上)

400 阅读3分钟

索引就是为了提高数据查询的效率,就像书的目录一样。

索引的常见模型

  • 哈希表
    • 只适用于等值查询的场景,对于范围查询只能走全表扫描。
  • 有序数组
    • 等值查询和范围查询场景中的性能都非常好。
    • 插入性能太差。所以适合静态存储引擎,如2017年城市人口信息。
  • 二叉树
    • 查询复杂度是O(log(N))
    • 二叉树的搜索效率是很高的,但是大多数的数据库存储不会用二叉树。因为索引不止存在内存中,还要写到磁盘上。想象一棵100万节点的平衡二叉树,树高20,一次查询可能需要访问20个数据块。从磁盘随机读一个数据块就需要10ms左右的寻址时间,那么20个数据块的访问时间就会达到200ms。

InnoDB的索引

在InnoDB中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。

在InnoDB中,索引使用B+树的索引模式。B+ 树能够很好地配合磁盘的读写特性,减少单次查询的磁盘访问次数。

img

左边是主键索引,右边是普通索引。主键索引的叶子节点存的是整行数据,普通索引的叶子节点存的是主键的值。

  • 如果语句是 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+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。

所以使用自增主键的重要性就体现在这里了。每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂。

显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

  • 适合用业务字段直接做主键的场景
    1. 只有一个索引
    2. 该索引为唯一索引

总结

  • InnoDB使用B+树作为索引模型。因为B+ 树能够很好地配合磁盘的读写特性,减少单次查询的磁盘访问次数。
  • InnoDB是主键索引组织表
  • 推荐使用自增主键