图说数据库索引

数据库储存结构

常见的数据库储存空间的基本结构是数据页,一个数据页的大小一般为 16KB。数据页的头信息中,保留着前向指针和后向指针,分别指向前一页和后一页,数据页之间形成了双向链表。
在数据页内部,存储了用户记录(即使用数据库插入的一条条记录),记录按照主键值大小升序排序。每条记录都有一个后向指针,指向后一条记录,因此记录之间形成了单向链表。值得注意的是,数据页还会自动增加两条额外的记录,分别为最小记录和最大记录,规定最小记录指向数据页中主键值最小的记录,数据页中主键值最大的记录指向最大记录。
在这里插入图片描述

数据页内的查找

  • 单页查找
    可以注意到,每个数据页内的主键都是有序的,如果需要查找某一个主键的值,可以使用二分法很快地定位到记录。但是要查找非主键列的值,因为非主键列并不是有序的,所以只能从最小记录开始依次遍历整页,页的记录量很大,所以效率会很低。
  • 多页查找
    多页查找,需要先定位到页,再定位到页内的记录。由于页是无序的,所以要从第一页开始,遍历每一页,在每一页中使用上述的单页查找方法,直到找到指定的记录。

可以看出,上述的方案确实存在效率上的问题。一个比较好的方式是参照页内主键快速定位的方法建立索引目录页。

索引的建立

在这里插入图片描述
在数据页的上方,增加了目录页来方便定位页码。目录页至于两列记录,一列为key,即它指向的数据页的键值最小的记录,另外一列为它指向的数据页的页码。这样以来,就可以在上述多页查询的第一个步骤中,利用二分法快速定位到页码。而这些目录页该如何保存呢,我们可以把它当成一条条记录,保持着单向关系,再存进一个数据页中,数据页间保持着双向关系。如下图所示:
在这里插入图片描述
现在我们拥有两层的数据页,再加一层呢,是不是越来越像树啦?没错,它是一棵 B+ 树。
在这里插入图片描述
用户数据都被存放到最底层的节点上,即叶子节点上。而非叶子节点,则存放的索引,最上面的节点为根节点。有了 B+ 树以后,我们就可以很轻松地从根节点出发去定位到记录的页码了。

索引的类型

  • 聚簇索引:以主键值为排序依据的索引
  • 二级索引:以非主键值为排序依据的索引
  • 联合索引:以多个列为排序依据的索引

其中,二级索引和联合索引的叶子节点不会带上完整的用户记录,而是只会带上主键,所以在经过二级索引和联合索引的查找后,只能拿到主键值,而不能拿到完整记录。如果要拿到完整记录,就需要用主键值再到聚簇索引中用主键值查一遍,这个操作也叫做 “回表”。

之所以二级索引和联合索引的叶子节点不带上完整的用户记录,是因为如果带上完整的用户记录以后,相当于这个 B+ 树把所有的用户记录都拷贝一遍,非常浪费空间。而每次我们建立二级索引或联合索引的时候,都会新建一棵 B+ 树。

索引的使用

索引在用于范围匹配搜索、排序、分组的情况下,比较有用,仔细想想键值的有序性就可以知道了。
而说到这,就要说起业务代码中需要用到多个字段不重复插入,就需要多个列作为联合索引唯一,在 greenDao 中的使用是这样的

@Entity(
    indexes = {
       @Index(value = "column1,column2,column3", unique = true)
    }
)

在执行 insertorupdate 就可以满足业务要求了。也可以使用 IGNORE 关键字或者ON DUPLICATE KEY UPDATE 来更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章