数据库之索引的数据结构

本文介绍了数据库索引的主要数据结构,包括二叉查找树、B-Tree、B+Tree、Hash索引和位图索引。重点讲述了B+Tree在数据库中的优势,如降低磁盘读写代价、查询效率稳定和利于范围查询。同时也提到了Hash索引的优缺点,如快速定位和不支持范围查询。位图索引适合用于低选择度字段的统计场景。

索引的数据结构主要有以下几种:
(1)生成索引,建立二叉查找树/二叉排序树/二叉搜索树进行二分查找;
(2)平衡二叉树,红黑树;
(3)生成索引,建立B-Tree(B树/B-树)结构进行查找;
(4)生成索引,建立B+ - Tree(B+树)结构进行查找;
(5)生成索引,建立Hash结构进行查找;
(6)生成索引,建立位图结构进行查找。

1、 二叉查找树

在这里插入图片描述

二叉查找树的特点:
(1)二叉查找树的每一个节点的值都大于其左子树上所有节点的值,且小于其右子树上所有节点的值;
(2)二叉查找树的每一个节点的左、右子树也分别是一棵二叉查找树。

平衡二叉查找树的特点:任意一个节点的左、右子树的高度(从该节点到叶子节点的最长路径的边数)之差不超过1(<=1)。

二叉查找树是通过二分查找,时间复杂度是O(logn),其中n是节点数。

2、 B-Tree(B树/B-树)

在这里插入图片描述

B-Tree(B树/B-树)是一个平衡多路查找树,树中的每一个节点至多包含m个子节点,称为m阶B-Tree(B树/B-树),如上图所示m=3即3阶B-Tree(B树/B-树)。节点中存储了关键字和指向每一个子节点的指针。

B-Tree(B树/B-树)的定义如下(其目的是为了让每个索引块尽可能地存储更多的信息,并且尽可能地减少I/O次数):
(1)根节点至少包含2个孩子;
(2)树中的每个节点至多包含m个孩子(m>=2);
(3)除了根节点和叶子节点以外,其他节点至少包含ceil(m/2)(表示m/2向上取整,即取大于等于m/2的最小整数)个孩子;
(4)所有的叶子节点均位于同一层上;
(5)假设每个节点存储了n个关键字信息,其中
a)K[i](i=1,2,…,n)为关键字,且关键字按照升序顺序排序,即k[i-1]<K[i];
b)每个节点存储的关键字的个数n必须满足:ceil(m/2) - 1<=n<=m-1;
c)非叶子节点的指针P[1],P[2],…,P[m],其中P[1]指向关键字小于K[1]的子树,P[m]指向关键字大于K[m-1]的子树,其他指针P[i]指向关键字属于(K[i-1],K[i])的子树。

B-Tree(B树/B-树)的时间复杂度为O(logn),其中n是节点数。

3、 B+ - Tree(B+树)在这里插入图片描述

B+ - Tree(B+树)的定义(B+树能够比B树在每一个索引块中存储更多的关键字信息,并且尽可能地减少I/O次数)在B-Tree(B树/B-树)的定义的基础上有如下变化:
(1)非叶子节点中指向子树的指针个数与关键字个数相同;
(2)非叶子节点中指向子树的指针P[i]指向关键字属于[K[i],K[i+1])的子树;
(3)非叶子节点仅用来索引,所有数据(按照大小顺序排列)都保存在叶子节点中(对B+树的检索都是从根节点开始,到叶子节点结束,所有的搜索都只会在叶子节点处终结,由于非叶子节点仅用来索引而不存储数据,因此可以存储更多的关键字信息;而B树可以在任意节点处终止);
(4)所有的叶子节点均有一个链指针指向下一个叶子节点(支持范围查询,一旦定位到某个叶子节点,便可以横向地、跨子树地去做范围统计了)。

B+树相比于B树、二叉查找树在文件系统以及数据库系统中更有优势,更适合做存储索引,主要原因如下:
(1)B+树的磁盘读写代价更低:因为B+树的非叶子节点仅用来索引而不存储数据,因此可以存储更多的关键字信息,如果将同一个内部节点中的关键字存储在同一个盘块中,则这个盘块可以容纳的关键字也就越多,一次性读入内存中需要查找的关键字也就越多,相对来说磁盘读写次数也就降低了;
(2)B+树的查询效率更稳定:因为对B+树的检索都必须走一条从根节点到叶子节点的路径,所有的搜索都会在叶子节点处终结,所有关键字的查询长度相同,因此各个数据的查询效率也就相同,都是稳定的O(logn);
(3)B+树更有利于数据库的扫描:因为B+树的所有叶子节点均有一个链指针指向下一个叶子节点,因此只需要遍历叶子节点就可以实现对全部关键字的扫描,范围查询效率更高。

4、 Hash索引

在这里插入图片描述
一些数据库的存储引擎还支持Hash这种数据结构作为其索引,Hash这种数据结构通过计算哈希函数只需一次定位就可以找到所要查询的数据所在的桶(buckets),而B+树这种数据结构在检索时需要访问根节点、非叶子节点、一直到叶子节点处才能访问到我们所需要的数据,这样可能会经过多次I/O访问,因此理论上Hash索引的查询效率要比B+树索引高。

如上图所示,比如我们想要访问Keys为Sandra Dee的信息,那么就可以通过一次哈希函数的计算就定位到相应的桶(buckets)即第152号桶中,然后将第152号桶的entries(是一个链表)全部加载到内存中,最后就可以顺着Join Smith的指针定位到Sandra Dee了。

Hash索引的缺点:
(1)仅仅能满足“=”和“IN”,而不能进行范围查询(由于Hash索引比较的是经过哈希运算之后的Hash值,因此只能用于等值过滤,而不能用于范围查询。因为经过哈希运算后的Hash值的大小关系并不能够保证与哈希运算前的键值的大小关系完全一致,如上图中的Join Smith和Sandra Dee经过哈希运算后就得到了相同的Hash值,但这并不能表示它们实际的大小关系)。
(2)无法被用来避免数据的排序操作(由于Hash索引中存放的是经过哈希运算后的Hash值,而Hash值的大小关系并不一定与哈希运算前的键值的大小关系完全一致,因此数据库无法利用索引的数据避免任何的排序操作)。
(3)不能使用部分索引键查询(对于组合索引即一个索引中包含多个列的情况,Hash索引在计算Hash值的时候是将组合索引键合并之后再一起计算Hash值,而不是单独计算Hash值。当使用组合索引的前面的一个或者几个索引键进行查询的时候,Hash索引也无法被利用;而B+树索引是支持利用组合索引的部分索引键的)。
(4)在任何时候都不能避免表扫描(Hash索是将索引键通过哈希运算,将哈希运算结果的Hash值和所对应的行指针信息存放在一个buckets中,由于存在不同索引键在经过哈希函数运算之后可能得到相同的Hash值的情况,因此即使取到满足Hash值的buckets中的那些数据,也无法在Hash索引中直接完成查询,还是要访问buckets中的实际数据进行相应比较)。
(5)遇到大量Hash值相等的情况时性能并不一定就比B+树索引要高(对于选择性比较小的索引键,如果要对其创建Hash索引,那么就可能会存在大量记录指针信息存放于同一个buckets中的情况,这样要定位到某个记录就会非常麻烦,从而造成整体性能低下。在极端情况下,所有的索引键在经过哈希运算之后都得到了相同的Hash值,映射到了同一个buckets中,这样在访问该buckets中的链表中的最后一个元素时,就会变成线性的O(n)的时间复杂度了)。

5、 位图索引

在这里插入图片描述
当表中的某个字段只有几种值时,比如性别只有男、女两种情况,如果只是为了在该字段上实现高效地统计,此时可以考虑使用位图索引。但目前主流的数据库中支持位图索引的数据库较少,比如Oracle数据库。位图类似于B+树,在叶子节点处包含有指定的位图段,由于只需要存储是与否,因此可以使用一个bit位来表示,因此理论上在一个叶子块中可以存储很多的bit位来表示不同的行。

位图索引的局限性:
(1)位图索引只适用于表中某个字段仅有几种值(或者几种状态)的情况;
(2)位图索引的锁的粒度非常大,当需要新增或者删除一条记录时,通常会锁住与其在同一个位图中的其他操作,因为某行的位置顺序可能会由于插入或者删除一条记录而发生改变,因此不适用于高并发的场景,而只适用于并发较少且统计较多的场景。

总结:通常情况下,索引的数据结构主要是B+树结构,比较小众的索引的数据结构还有Hash结构和位图。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值