您的位置:首页 > 数据库

SQL Server 查询优化(3)_索引的设计与使用

2009-12-16 21:29 609 查看
一、索引的作用
1、帮助检索数据;
2、提高联接效率;
3、节省ORDER BY、GROUP BY的时间;
4、保证数据唯一性(仅限于唯一索引)。

二、索引的设计
在确定要建立一个索引时,首先我们要确定它是聚集还是非聚集、单列还是多列、唯一还是非唯一、列是升序还是降序、它的存储是如何的,比如:分区、填充因子等。下面逐条来看:
1、聚集索引
(1)首先指出一个误区,主键并不一定是聚集索引,只是在SQL SERVER中,未明确指出的情况下,默认将主键定义为聚集,而ORACLE中则默认是非聚集,即堆表,因为SQL SERVER中的ROWID未开放使用。对于DML比较频繁的表,建立主键时,不建议指定聚集选项,使用堆表可获得更好的DML性能;
(2)聚集索引适合用于需要进行范围查找的列,因为聚集索引的叶子节点存放的是有序的数据行,查询引擎可根据WHERE中给出的范围,直接定位到两端的叶子节点,将这部分节点页的数据根据链表顺序取出即可;
(3)聚集索引尽量建立在值不会发生变更的列上,否则会带来非聚集索引的维护;
(4)尽量在建立非聚集索引之前建立聚集索引,否则会导致表上所有非聚集索引的重建;
(5)聚集索引应该避免建立在数值单调的列上,否则可能会造成IO的竞争,以及B树的不平衡,从而导致数据库系统频繁的维护B树的平衡性。聚集索引的列值最好能够在表中均匀分布;
(6)选择作为聚集索引的一个或多个字段,数据长度不要太大,否则会导致及非聚集索引占用更多的存储空间,降低非聚集索引遍历的效率;

2、非聚焦索引
(1)非聚集索引适合用于需要进行等值查找的列,因为非聚集索引的叶子节点存放的是有序的索引列与书签的映射行,查询引擎可根据WHERE中给出的值,得到书签,继而定位到数据行;
(2)覆盖索引(Covering Index),是非聚集索引的一种特殊且高效的应用,就是将需要返回的数据列设计成组合索引,在SELECT时只查询索引中存在的数据列,这样就能形成索引覆盖,因为索引行中已经包含了想到的数据,不需要再进行书签查找;
在SQL SERVER 2005及以上版本中,提供了INCLUDED关键字,可以在非聚集索引中包含更多列,也是覆盖索引的一个有效引申;
(3)非聚集索引建立在值具有单调性的列上,比如:自增列(单调递增),可以减少索引的外部碎片及索引结构的维护;

3、复合索引
(1)复合索引建立在多个列上。上面已经讲过,在非聚集索引中,可以利用覆盖索引来提高检索的效率,但如果组合索引的列太多的话,那么对于这个索引的维护成本也会加大,DML的效率将会下降,而且索引的查找路径会变长;
(2)在创建复合索引时,应该将高选择性的列放在前面,即作为引导列;

4、唯一索引
(1)再指出一个误区,聚集索引并不一定是唯一索引,由于SQL SERVER将主键默认定义为聚集索引,事实上,索引是否唯一与是否聚集是不相关的,聚集索引可以是唯一索引,也可以是非唯一索引;
(2)将索引设置为唯一,对于等值查找是很有利的,当查到第一条符合条件的纪录时即可停止查找,返回数据,而非唯一索引则要继续查找,同样,由于需要保证唯一性,每一行数据的插入都会去检查重复性;

5、分区索引
(1)SQL SERVER从2005引入的分区表的概念,对于在分区表上建立的索引,无论是否包含分区列,在未指定分区方案或文件组的情况下,均会使用分区表的分区方案来创建该索引。这一点与ORACLE正好相反;

6、其他索引
(1)筛选索引,在ORACLE中叫域索引,这是SQL SERVER 2008新增的功能,适用于表中数据密度不高的列来创建索引,比如:表中某列大多是NULL或某相同值,那么此时可通过WHERE关键字来筛选这些相同值来创建索引,这样在对非相同的值进行检索时,即可以用到这个索引;
(2)计算列索引,在ORACLE中叫函数索引,如果表中存在计算列,但想要对计算列进行检索,可在计算列上创建索引,但前提是必须要先持久化该计算列;
(3)索引视图,在ORACLE中叫物化视图,我们知道视图的数据都是来源于基础表,在SQL SERVER中对视图建立索引,事实上就对视图进行了物化,然后才创建索引,索引视图多用于静态数据的查询,毕竟物化视图的更新是比较麻烦的;
(4)位图索引,对BOOL型字段建立索引,在SQL SERVER中暂未提供这样的功能;
(5)XML索引,对XML列只能创建XML索引;
(6)全文索引,LOB类型列上无法建立普通索引,比如VARCHAR(MAX)、TEXT、IMAGE,如果需要检索可以考虑建立全文索引,当然全文索引也可以用在非LOB类型的列上;

7、索引参数
(1)填充因子,索引的叶子节点的填充程序,对于DML比较频繁的表,考虑预留一定的页空间,以避免过多的页拆分,但如果预留空间太大,会放大查询的成本。索引的中间节点如果也使用填充因子,可以打开PAD_INDEX选项;
(2)忽略重复键,这个选项通常用于去重处理,对于将要插入到表中的行,如果存在相同索引键,则抛弃;
(3)根据业务查询需要,决定列升序还是降序,通常对于单列索引存在正向或反向扫描,但在复合索引的非引导列中检索时,如果存在需要倒排的查询,则在建立索引时应选择降序;
(4)在索引的存储上,将聚集和非聚集索引定义在不同磁盘分区的文件组上,减少IO竞争,亦可利用多CPU并发,但目前通常都是RAID5+1(1备份5中的一块硬盘)的存储,数据存放本就已分散,这样做的意义并不是太大。

8、索引列选择
(1)参考[索引的作用]选择索引列,比如:如果表中存在外键,考虑在该列上建立索引,可增加参照完整性检查的速率,同样,如果存在连接,也可提高连接的速率;
(2)索引选择性公式:selectivity=unique keys/rows,一般当选择性低于0.1即10%时,查询优化器拒绝使用该索引,比如:BOOL类型的列。此处有一个矛盾,有可能我们无法知道当前列的selectivity,那么只能采用估算的方式,比如采用SQL SERVER 2005的TABLESAMPLE进行数据采样等;
(3)在面对一个多条件的查询时,应该选择过滤性较强的字段作为单列索引,或作为复合索引的引导列;
(4)在长度较小的数据类型上建立索引,这样每条索引存储所占用的空间就会变小,每个索引页上就能够存储更多的索引行,缩短索引查找的路径;
(5)不要在一个表上建立太多的索引,索引的维护会影响DML的效率;

三、索引的使用
1、避免无效搜索表达式
(1)WHERE条件中将索引列放在表达式中:如fun(c1) = 1,c1+c2 = 2等;
(2)索引列在未知数值起点的LIKE运算符中:如Like ‘%abc’或like ‘%abc%’;
(3)包含否定运算符的表达式,如:<>、not in/exists/like;
(4)NULL表达式,如:is null、is not null;
总之,无法让检索值与索引值,进行比较运算的表达式,都为无效搜索表达式。

2、复合索引的引导列
比如复合索引列为(c1,c2,c3),则在WHERE条件中必须指定c1,才会用到该复合索引;

以上两点总的原则就是:构造索引查找,避免索引扫描,我们通常所说的:能不能用到索引,也应该是指索引查找,而不是索引扫描。

3、尽量使用等值运算符
比如在使用WHERE c1>1时,SQL SERVER会尽量去将它转会为WHERE c1>=2(如果整形的话),以给索引查找一个起点,如果无法隐式转换为>=,则会以c1>=1为起点,查找完成后再踢除=1的数据;

4、表达式的顺序
在WHERE条件中包含多个表达式时,应该将过滤性最强的表达式放在靠近WHERE的位置,通常这样的表达式中的列,也会选择在上面建立索引,因为在一个WHERE子句中只有一个表达式是可以使用索引的,其他的表达式都是基于索引查找结果集的过滤,所以应尽量保证有效索引的使用。尽管查询优化器会去识别,然后自动去重排表达式的顺序,但我们应该养成一个好的习惯。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: