“索引”这个名字,想必大家都耳熟能详了,众所周知,索引最大的用途就是提升数据库的查询速度。或许,你会说,我曾经自己动手按书上讲的方法试验了一番,可是没有感觉有多大速度的提升呢?这完全是可能的,因为索引就像是一门非常厉害的武功招式,如果我们想发挥其最大的功力,光凭招式的纯熟是远远不够的,我们还必须同时修炼其高深的内功方可……
就上面的问题,首先,我们一般的学习和试验情境中,很难会遇到大数据量的情况,什么叫大数据量?10000条算不算大?10万、100万呢……
就个人目前经历的情况来看,一般只有上了10万这个级别,才能初现索引的优势,这也就是说,当我们通过小数据量数据库进行实际操作的时候,可能只有通过使用函数的方法,才能在毫秒级别上得到一个比较满意的结果,但如果想从实际应用角度获取“真实”的索引效果,大数据量是一个必须的前提。
学习讲究从0开始,我们就从索引的“招式”讲起……
首先,请大家回忆一下,我们在使用汉语词典查找一个汉字的时候,通常可以怎么做?
对了,我们一般有两种方法:首先,对于我们认识的字,我们可以直接通过其拼音的首字母进行初步定位,然后再通过后面的拼音进行逐次定位,最终找到汉字,如“索”字,我们首先通过其拼音“suo”可以知道,我们必须首先找到s,然后再翻找u,最后找到o,这时,我们再翻一两页一般就能找到我们要找的汉字了;但如果我们遇到一个不认识的字,又该咋办呢?例如“引”这个汉字,我们可以通过笔画数或者偏旁部首进行查找,即通过将笔画数相同的所有汉字或者偏旁都一样的所有汉字进行集中,并在其后附加上该字的具体页码,这样,当我们逐个汉字进行查找时,一旦找到这个汉字,我们就能马上定位其所在的页码,可谓相当精确!
我们终于在字典中找到了“索引”这两个汉字,先让我们稍微庆祝一下,因为我们已经基本掌握了索引的原理了!你不信?好,让我们细细谈来……
无论是通过拼音直接查询,还是通过笔画,抑或是偏旁查询,我们都是通过实现将这些汉字通过某一种规则进行编排,然后,才能让我们顺利、快速地找到我们要找的汉字,那你有没有想过有这么一本字典,它包含很多的汉字,但是汉字的前后顺序没有任何规则。如果硬要你从这个字典中查到“索”这个汉字,你会怎么做?撞大运,随机进行抽取?虽然也是个办法,但毕竟你能在有限次数内,恰翻到准确页码的几率万分渺茫!最笨且最有效的方法就是从字典的第一页逐页进行查找,直到找到那个汉字为止!如果你要找的汉字恰巧在首页,你真是人品大爆发了,但如果你要找的汉字恰巧在最后一页呢……
下面让我们把索引和查字典关联起来进行理解,那么得到如下的对应关系:
字典 索引
拼音查找 聚集索引
笔画或偏旁查找 非聚集索引
最好记着这个对应关系,一旦你对索引的概念有一点迷糊的时候,就翻起手边的字典查两个字,绝对有效!这就是武功招式的秘籍!
索引共分为两招,第一招为聚集索引,第二招为非聚集索引。
聚集索引的排列顺序和磁盘上物理数据存储的顺序是一致的,它拥有最快的查询速度,且限定每一个数据表只能有一个聚集索引,这很显然,因为物理数据只能有一种排序规则,对应到字典上,按拼音进行编排即为聚集索引,而字典的数据内容即可理解为物理数据。
所谓非聚集索引,即其只将设定的属性列,按照设定的顺序进行排列后的结果数据保存到数据表中,我们可以将其理解成字典中的笔画或偏旁查询页,其中只保存有选定列的内容和其在磁盘中的物理地址,当我们找到所要找的数据时,也就意味着我们已经找到了它的物理存储地址!相比聚集索引来说,它是一种非常精确的查找方式。但是,有一点需要说明,因为非聚集索引需要一定的物理空间来保存排序后的结果集,所以,选择内容短小,经常用于查询的列一方面提高了查询速度,再者也不会对数据库的容量有过多的影响。
很简单吧,索引就是这么简单!既然我们已经把索引的招数熟记于心了,是时候提升我们内功了。所谓内功即我们在何时,对那些属性列建立何种索引?
在SQL Server中,数据库会自动为数据表的主键列建立聚集索引:我们通常情况下,会为一个数据表建一个ID属性列,用于唯一标识数据行内容,这样做可以让我们在查看数据的时候获得方便,但对于数据库的查询性能可没有啥帮助,让我们回想下字典的原理吧,如果一个拼音就是一个页码的话,我要想查找一个拼音的时候,只能退守到最原始的从头至尾查找方式!所以,默认的并不一定是最佳的,我们一定要理解这个概念。
下面就我们日常遇到的一些情况进行总结,并说明使用何种索引更能有效提升性能(只是一般情况,但仍需要具体问题具体分析!):
动作描述 | 使用聚集索引 | 使用非聚集索引 |
列经常被分组排序 | 应 | 应 |
返回某范围内的数据 | 应 | 不应 |
一个或极少不同值 | 不应 | 不应 |
小数目的不同值 | 应 | 不应 |
大数目的不同值 | 不应 | 应 |
频繁更新的列 | 不应 | 应 |
外键列 | 应 | 应 |
主键列 | 应 | 应 |
频繁修改索引列 | 不应 | 应 |
尤其要注意其中的“小数目不同值”和“大数目不同值”,这往往需要我们的经验来进行区别,没有一个具体的衡量标准。
索引虽然有诸多好处,但过多地建立索引有的时候可能会获得相反的结果,例如可能导致数据库容量过于臃肿、导致数据库正常的INSERT,UPDATE和DELETE等操作的性能大大降低等,这就要求我们必须要多结合实际的情况进行分析,以建立最优的索引。
当然,如何编写SQL语句也是影响索引性能的一个重要方面,下面有几点需要特别留意:
1. 日期属性列,不会因为有分秒差别而减慢查询速度
2. 使用LIKE比较进行查询时,如果模式以特定字符串如“abc%”开头,使用索引则会提高效率;如果模式以通配符如“%xyz”开头,则索引不起作用
3. OR会引起全表扫描,且和IN的作用相当,但建立索引仍旧会有比较明显的效果提升~
4. 尽量少用NOT
5. EXISTS 和 IN的执行效率是一样的
6. 用函数charindex()和前面加通配符%的LIKE执行效率一样
7. UNION并不绝对比OR的执行效率高
8. 字段提取要按照“需多少、提多少”的原则,避免“SELECT *”
9. COUNT(*)不比COUNT (字段)慢
10. ORDER BY按聚集索引列排序效率最高
11. 多用“TOP”进行数据提取,可提高效率
最后还是那句话,大家一定要活学多用,才能逐渐领悟索引的内功的奥妙,虽然索引的用法多变,但使用的原则不变,那就是“简单才是王道!”祝大家学习顺利!