数据库索引与b+树
数据库索引详解
索引
当我们在设计数据库的时候,对表的一些属性有时会加上索引,但索引为什么能提高检索速率呢?是不是用了索引就一定可以提高效率呢?不同索引之间有什么区别呢?搞懂这些问题是灵活运用索引的必备条件。接下来,我们将一 一进行讨论。
一.索引的本质
索引也分为不同的种类,而且也有不同的分类方法,比较常用的是普通索引和聚集索引。
1.普通索引
其实对某字段建立了索引就相当于是对该字段新建立了一个表,这个表里的元素是安照这个字段有序排列。这样有什么好处呢?好处就在于如果我们select的时候要搜索该字段,那就会在这个索引表中先查找,因为索引表是有序的,所以在检索该字段的时候就是二分搜索,速度自然会比在原表上快,然后如果我只需要这一个字段的话,查询就可以结束了,但如果还需要除索引字段的其他字段的话,那么就会根据这个索引表的字段对应到主表中,然后再获取。
看了上面讲的,是不是感觉有点迷茫?下面看一下图就会清晰很多。
(图片来源于百度)
大家可以看到这里我们以Col2建立索引之后右边有一颗二叉树,可能大家会问不是说好了是一张表吗,怎么又是二叉树了,好吧表本身就是一种树形的数据结构存储,虽然实际上很少会选取二叉树,但此处方便讲解。可以看到Col2单独的一棵树,然后每一个节点对过来是一条记录,如果我们执行 select Col2 from tablename where Col2=34;那么直接在右边的树中二叉搜索,找到了就可以返回了。如果我们执行 select * from tablename where Col2=34;那么可以看到需要的不仅仅是Col2这一个字段,那么还是先在二叉树中查找,然后找到了之后对应到主表中,然后返回整条记录。
1.索引的数据结构
通过上面的图我们可以看到,索引的本质其实就是新建了一张表,而表本质上的数据结构就是树形结构,所以索引也是树形结构。但实际运用中并没有谁用红黑树,avl树这种数据结构,一般是b+树,接下来给大家大致介绍一下b+树的构成。
(图片来源于百度)
b+树在构建时和我们之前提到的二三树很像,只是有一些改进,b+树的非叶子节点不包含value的信息,也就是说非叶子结点只起到一个导航的作用,所有的value放在了叶子结点里,这样由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。通常会将b+树进行优化,增加顺序访问指针。
(图片来源于百度0)
在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。做这个优化的目的是为了提高区间访问的性能,例如图中如果要查询key为从18到49的所有数据记录,当找到18后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提到了区间查询效率。
可以看到b+树对于表的存储是一种很方便的数据结构。那么为什么不用红黑树呢,因为数据量大的时候,会导致这种二叉树深度太深,io次数会很多,层数很少的b+树可以有效降低io次数。
聚集索引
聚集索引和普通索引是不一样的,聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚集索引,因为一个表的物理顺序只有一种情况。意思就是说上面的普通索引我们可以看到是另建了一个表,然后当查询到了索引没有覆盖到的字段的时候是将这个字段映射到了主表中然后进行查询的。而聚集索引建立后主表本身就会按照这个索引的结构来存储,意思就是说主表直接就按这个来存了。这也是为什么聚集索引一定是唯一的原因,因为一张表中只能有一种存储方式。
聚集索引与普通索引
两种索引谁更快呢?这当然是没有悬念的,聚集索引更快咯,因为普通索引查到没有覆盖的字段的时候需要向主表中映射过去,然后再获取,而聚集索引因为其本身就包含了所有数据,所以一次就好~
主键与聚集索引
在我们新建一个表时,如果没有定义主键,那么表格的数据是顺序线性存储的,在定义的主键之后,因为主键默认有索引,并且在很多平台上默认是聚集索引,所以在主键定义的时候就会把整个表变为一个树形结构(如果主键是聚集索引),但要知道的是主键不一定是聚集索引,也可以是普通索引,只是很多平台默认为聚集,不要盲目划等号。
索引的利弊
那么索引既然这么快是不是越多越好呢?不存在的,因为索引本身是一个数据表,那么在插入或删除的时候就涉及到了索引表的改变,b+树的插入删除涉及到很多节点操作,或许会消耗很多时间。所以我们对于常改变的字段不宜建索引,而对于改动较少的字段就很合适,在设计表的时候我们要灵活选取,才能高效。