通俗易懂讲索引(二)

原创文章转载请注明出处!

1.2 稀疏索引

由于稠密索引中索引项和记录都是一一对应的,这导致索引项的数量过多。那能不能不一一对应,要是一个索引项能对应100条记录那么索引项的数量将降低100倍。答案当然是能,而这正是稀疏索引的思路即一个索引项对应n条记录。

这里写图片描述

那应该怎么建立索引呢?仍然使用前面商品列表的例子。如果商品记录表中有5亿条记录,并且记录都是按照商品编号从小到大排序的(这可是线性索引的基本要求),我们可以将这些记录进行分组,若每组100条记录,可以获得500万条记录。分组完成后,跟前面建立一样,我们抽取记录和它的存储地址组成索引项,只是这次我们只抽取每组的第一条记录。这样我们就建立了一个稀疏索引,索引项只有500万条,占用空间约50M,这可比稠密索引的5G降低了很多啊,内存表示毫无压力。而且由于索引项变少,插入或删除时索引的维护成本也降低了。那怎么搜索呢?

比如我们要查找编号为yyy的商品,怎么查?我们拿这个编号和索引项的编号进行比较,如果发现yyy大于第i个索引项,但是小于第i+1个索引项,说明yyy这个编号在第i组中。我们通过第i个索引项拿到其存储地址,然后遍历该组中的100项记录,若编号存在则一定能找到该商品记录。

上面说了这么多的稀疏索引的好处,那稀疏索引就没有缺点么?当然是有的,那就是其搜索速度要比稠密索引慢,理论上来说最坏的情况下其查找次数约为klogn, k为每组记录的数量。那前面5亿条数据的例子,查找次数约为2225.3,稠密索引则约为28.8,前者是后者的约77倍,但是两者的时间复杂度都是O(logn),所以有时计算渐进复杂度略去的常数影响也不小。从下图中可有看出随着k的增加查找所需次数也随之增加。

这里写图片描述

除了查找效率上的问题外,稠密索引在数据量进一步增大,如500亿条时,每组100条记录,其索引项的数量仍可能会达5亿,存储空间要约5G。原来在稠密索引中的存储问题就再次出现在了稀疏索引中。有人可能说我分组变大一点不就行了么,然而每组数据量过大时会占用很多块仍会反复读取硬盘,而且分组变大也会导致查找次数增加,查询效率仍然不高。因此稀疏索引在数据量不是特别大的情况下是可以使用的,但是当数据量超过一定量时其弊端也就显现出来了。那这么大的数据量下就没有办法了么?当然有!接下来我们就说一下可以解决这一问题的多级索引。

2 多级索引

从前面分析可知,在数据量大到一定程度的情况下,稠密索引和稀疏索引索引量大无法放到内存的问题,此时索引只能放在硬盘中,查询时反复读取硬盘导致查询效率变低。如果稠密索引分布在10万个块中,用二分法查询需要读取硬盘log(100000)约130次。由于机械硬盘读写存在机械性的操作,寻道、旋转延迟和数据传输等都会导致其数据读取速度相对内存要低很多,一般情况下一次读取要3ms到15ms。因此,一次查询平均需要1170ms,这意味着1秒一次查询都无法完成。所以,大数据量的情况下提升查询速度的关键是减少硬盘的读取次数。那应该怎么处理呢?

假如我们已经建立了一个稠密索引,它一共占用10万个块。然后,我们在此基础上再建立一个稀疏索引,每个索引项指向一个块,我们可以得到10万条索引项,若仍按照前面说的索引项占1kB,那这个稀疏索引需要大约需要100M。如果内存够用,可以把这个稀疏索引都放到内存中,那么查询时只需要读取一个块,所需时间平均约9ms。一秒钟可以查询100多次。这可比一秒查一次快很多了。但是,有人说了,我内存没法预留100M的空间放索引,100M也得放到硬盘上,那怎么办?那也有办法,假如这100M的索引占用1000个块(注意:文中提到的索引所占用的块数并未根据块的一般大小和索引大小进行计算,只是一个假设),我们在刚才建立的稀疏索引的基础上再建立一个稀疏索引,同样该索引的索引项分别指向那1000个块,这样这个稀疏索引一共有1000个索引项,占用空间不到1M。此时把它放到内存肯定没有问题了,进行一次查询,需要读取块两次,平均耗时约18ms,1秒内可以查询约55次,还是挺快的。

这里写图片描述

上面讨论中先在数据上建立了一个稠密索引,又在稠密索引上建立了一个稀疏索引,然后又在这个稀疏索引上建立了一个稀疏索引,这个整体是一个三层或三级的索引,如上图所示,像这样二级或二级以上的索引叫做多级索引,如图所示。其实多级索引也有不少种,像B+树索引,这些我们将在以后详细介绍。

3 聚集索引和非聚集索引

前面我们建立稠密索引的时候,把商品的编号和这个记录的存储地址拿出来并按编号排序后建立的。现在可能有两种情况,一种是商品记录清单本身就是按照商品编号排序的,也就是索引顺序和商品清单顺序一样,我们把这样的索引叫做聚集索引。另一种情况是商品记录本身并未按照商品编号排序,但是我们建立的索引是排过序的,也就是说索引顺序和商品记录的顺序是不一样的,我们把这样的索引叫做非聚集索引。

4 倒排索引(Inverted Index)

前面我们为用编号查找商品建立了不同的索引。但是如果现在我有编号从1到100的100篇文章每篇文章大约有5000字,我们想查找这100篇文章中包含 ”火箭“ 这个词语的有哪几篇,该怎么办?最简单的就是挨着文章搜一遍,这种方法可行,但是效率好像太差了些。如果我有1万篇文章甚至更多那不得等崩溃了。倒排索引就是针对这种情况出现的。

我们先把文章内容进行分割,然后提取出每篇文章的词语,然后把所有文章的词语汇总成一个表:

词语文章编号
火箭1,3,5
卫星1,2,7

加入要搜索”火箭“一词,立刻就能找到,是1,3,5三个编号的文章包含这个词语。但是光有编号还不行,得直到它具体的存地址。那我们就再根据编号建立另一个表:

文章编号存储地址
1xxx
2yyy
3aaa
4bbb
5ddd

这个表是不是很熟悉,对了,它就是一个稠密索引。有了这个表,我们就能根据文章编号一下找到存储文章的地方然后取得文章了。这个过程是不是很熟悉,这其实是很多搜索引擎工作的基本原理,当然实际上要比这个复杂多了。倒排索引这个翻译其实不太准确。Inverted的意思是我先从词汇查找到编号,然后再通过编号查找具体内容,而不是从编号直接查找到内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值