阅读导航
索引对于接触过数据库的人,都不会很陌生,但是说实话,也不一定很熟悉。先来介绍下索引的优点。
现在有一个数据库表[Words],有[WordID],[WordPage],[[WordName],[WordPronunciation] ,[WordMeaning],[WordSentence]五个列,假设有上万条记录。
现在,使用查询语句找到“boyce”的详细信息,使用语句
1: SELECT * FROM [Words]
2: WHERE [WordName] = ‘boyce‘
执行这个语句会发生什么?实际上程序在后台找一个单词“boyce”。数据库可能会查找表的每一行,是否存在一个单词“boyce”。但是,就算找到了表中一个单词“boyce”的行,数据库也不会停止检索,因为剩下的每一行都有可能是一个单词“boyce”的行,也就是说,知道所有行都被检索后,数据库才会停止检索并返回查询结果。其实就是做了一个全表检索。其实,如果一个表只有一百行甚至几千行数据,就算全表检索我们也不会又什么明显的感觉,但是随着数据的膨胀变大,几万行数据甚至更多时,整表检索可能就是一件令人恐惧的事情。如果这样的事情发生了,除了等待令人恐怖的检索,我们还可以做什么呢!使用肉眼去看,这样可能不是一个明智的做法,正常人干不出这事。
就像这个小标题一样,我们可以使用索引提高性能。索引是通过使用指针的指向减少了检索数据表记录数量来提高性能的。
索引是一个可以存储数据表列值的数据结构(通常都是R-tree)。索引创建在表中列上面。一个很重要的内容就是索引包含表中的列值,并且这些值被存储到了数据结构中。简单易记的一句话,索引就是数据结构。
那么可不可以说,索引就是B-tree呢?并不是这样的,除了有B-tree索引,还有hash索引、R-tree索引、bitmap索引
这是最常用的索引。因为,B-tree的索引在查找、删除、插入操作时的时间复杂度是对数时间。另外一个重要的原因是,可以把数据存储在B-tree中。但是,索引使用什么样的数据结构是由RDBMS(关系型数据库管理系统)决定的。有时候在创建索引的时候也可以指定索引的数据结构类型。
正因为索引是基于数据结构存储列值值的,所以检索这些值得时候会更快。B-tree 索引的数据结构也是一个有序的结构。索引提升性能的主要原因是什么呢?
现在在[WordName] 列上创建B-tree索引,这就意味着,在使用上面的语句
1: SELECT * FROM [Words]
2: WHERE [WordName] = ‘boyce‘
不会再进行全表的扫描。因为索引是可能是按照[WordName] 的字母进行了排序,这就表明,所有以”b” 开头单词的索引是挨着的。更重要的是索引中存储着指向列值实际数据行的指针。
这是可能被索引使用的另一个数据结构类型。在进行查找操作时,使用hash 索引。的效率很高。因此,当使用一个语句去比较字符串,然后返回结果集,这样的操作使用hash 索引是很快的。就像前面的语句
1: SELECT * FROM [Words]
2: WHERE [WordName] = ‘boyce‘
在列[WordName] 上创建hash 索引是一个很好的。这时,列值将插入到hash 表中和一个键对应,并和实际的数据行有一个映射关系,也就是该键是一个指向表中数据行的指针。hash 表实际是基于关联数组,假如有这样一个语句“boyce = 0×28936”,0×28936是关联到存储在内存中的boyce。在hash表索引中查找“boyce”的值并返回内存中的数据,要比检索整个表的[WordName]列值要快得多。
照这样的说法,是不是以后创建hash 索引好了?
其实不然
hash 表不是一个被排序的数据结构,很多类型的hash索引查询根本就没有性能的提升。比如。检索300页以内的所有单词。因为,hash 表擅长的是检索键值对,也就是说,检索语句检查相等性(如,“WHERE [WordName] = “boyce” ”)。在hash 表中的键值是没有排序的,在存储的时候也没有任何的排序规则。因为hash 索引不够灵活。所以,hash 索引不是默认索引的数据结构。
是不是,创建所有的索引使用默认的b-tree数据结构就完事大吉了呢?
下面的情况还是最好考虑使用hash 索引:
表中存在字段过长,这样的列是不适合创建索引的,创建索引的原则是索引不能太宽。
对于varchar(max)、nvarchar(max) 和 varbinary(max)的大值数据类型也不适合创建索引。
使用R-tree 数据结构的索引,这个主要是解决一些特定的问题。比如,找到方圆五百米的美女/帅哥,这是使用R-tree 索引,性能会有一定的提升。
还有bitmap 索引,在列值为Boolean值时,该类索引是相当有效的。一般用在选择性列上。
有一个问题:在索引中检索一个值(比如,boyce),是怎么样也找到该行其他的列的值呢([WordID]、[WordPage]……)?
可能会说,So easy!因为存在指针。
是这样的,还是让我来啰嗦一下。
索引中存储指向相应行的指针。这个指针是关联到一块内存,该内存中存储了相应数据在硬盘的地址。也就是说,添加为索引的列值是存储在索引中,指向相应数据行的指针也是存储在索引中。这就意味着,[WordName] 在索引中就是像这样(“boyce”,“0×82937”),那么,0×82937的地址就是“boyce” 所在行在磁盘中的地址。通过这个例子,可以看出, 单值得指针其实没有用的,是没有意义的,因为他不能得到相应数据行的值。
索引创建在表的列上,这个概念大家已经非常清晰了。索引只是存储了特定的列,并没有把表中所有的列全部存储到索引中。例如,在[WordName] 列上创建索引,这就意味着,[WordID],[WordPage]…… 没有存储在索引中。如果创建索引在所有的列上,那就相当于把 整个表复制了一份,这会占据很大的空间并且效率也很低。
现在我们知道,创建索引其实会占据一定空间的,越大的表,创建索引占据的空间越大。还有,在所添加、删除、和更新行的时候,都需要相应的维护索引,这样数据库的性能可能会降低。
一般的规则,被频繁检索的列,才在该列创建索引。