51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 4663|回复: 4
打印 上一主题 下一主题

谈索引使用的误区

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2007-9-11 18:22:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1、主键就是聚集索引
  这种想法笔者认为是极端错误的,是对聚集索引的一种浪费。虽然SQL SERVER默认是在主键上建立聚集索引的。

  通常,我们会在每个表中都建立一个ID列,以区分每条数据,并且这个ID列是自动增大的,步长一般为1。我们的这个办公自动化的实例中的列Gid就是如此。此时,如果我们将这个列设为主键,SQL SERVER会将此列默认为聚集索引。这样做有好处,就是可以让您的数据在数据库中按照ID进行物理排序,但笔者认为这样做意义不大。

  显而易见,聚集索引的优势是很明显的,而每个表中只能有一个聚集索引的规则,这使得聚集索引变得更加珍贵。

  从我们前面谈到的聚集索引的定义我们可以看出,使用聚集索引的最大好处就是能够根据查询要求,迅速缩小查询范围,避免全表扫描。在实际应用中,因为ID号是自动生成的,我们并不知道每条记录的ID号,所以我们很难在实践中用ID号来进行查询。这就使让ID号这个主键作为聚集索引成为一种资源浪费。其次,让每个ID号都不同的字段作为聚集索引也不符合“大数目的不同值情况下不应建立聚合索引”规则;当然,这种情况只是针对用户经常修改记录内容,特别是索引项的时候会负作用,但对于查询速度并没有影响。

  在办公自动化系统中,无论是系统首页显示的需要用户签收的文件、会议还是用户进行文件查询等任何情况下进行数据查询都离不开字段的是“日期”还有用户本身的“用户名”。

  通常,办公自动化的首页会显示每个用户尚未签收的文件或会议。虽然我们的where语句可以仅仅限制当前用户尚未签收的情况,但如果您的系统已建立了很长时间,并且数据量很大,那么,每次每个用户打开首页的时候都进行一次全表扫描,这样做意义是不大的,绝大多数的用户1个月前的文件都已经浏览过了,这样做只能徒增数据库的开销而已。事实上,我们完全可以让用户打开系统首页时,数据库仅仅查询这个用户近3个月来未阅览的文件,通过“日期”这个字段来限制表扫描,提高查询速度。如果您的办公自动化系统已经建立的2年,那么您的首页显示速度理论上将是原来速度8倍,甚至更快。

  在这里之所以提到“理论上”三字,是因为如果您的聚集索引还是盲目地建在ID这个主键上时,您的查询速度是没有这么高的,即使您在“日期”这个字段上建立的索引(非聚合索引)。下面我们就来看一下在1000万条数据量的情况下各种查询的速度表现(3个月内的数据为25万条):

  (1)仅在主键上建立聚集索引,并且不划分时间段:

       Select gid,fariqi,neibuyonghu,title from tgongwen

  
用时:128470毫秒(即:128秒)
 
  (2)在主键上建立聚集索引,在fariq上建立非聚集索引:

       select gid,fariqi,neibuyonghu,title from Tgongwen
              where fariqi> dateadd(day,-90,getdate())

  
用时:53763毫秒(54秒)

  (3)将聚合索引建立在日期列(fariqi)上:

       select gid,fariqi,neibuyonghu,title from Tgongwen
              where fariqi> dateadd(day,-90,getdate())

  
用时:2423毫秒(2秒)

  虽然每条语句提取出来的都是25万条数据,各种情况的差异却是巨大的,特别是将聚集索引建立在日期列时的差异。事实上,如果您的数据库真的有1000万容量的话,把主键建立在ID列上,就像以上的第1、2种情况,在网页上的表现就是超时,根本就无法显示。这也是我摒弃ID列作为聚集索引的一个最重要的因素。得出以上速度的方法是:在各个select语句前加:

       declare @d datetime   
       set @d=getdate()

  
并在select语句后加:

       select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())

  2、只要建立索引就能显著提高查询速度

  事实上,我们可以发现上面的例子中,第2、3条语句完全相同,且建立索引的字段也相同;不同的仅是前者在fariqi字段上建立的是非聚合索引,后者在此字段上建立的是聚合索引,但查询速度却有着天壤之别。所以,并非是在任何字段上简单地建立索引就能提高查询速度。

  从建表的语句中,我们可以看到这个有着1000万数据的表中fariqi字段有5003个不同记录。在此字段上建立聚合索引是再合适不过了。在现实中,我们每天都会发几个文件,这几个文件的发文日期就相同,这完全符合建立聚集索引要求的:“既不能绝大多数都相同,又不能只有极少数相同”的规则。由此看来,我们建立“适当”的聚合索引对于我们提高查询速度是非常重要的。

  3、把所有需要提高查询速度的字段都加进聚集索引,以提高查询速度

  上面已经谈到:在进行数据查询时都离不开字段的是“日期”还有用户本身的“用户名”。既然这两个字段都是如此的重要,我们可以把他们合并起来,建立一个复合索引(compound index)。

  很多人认为只要把任何字段加进聚集索引,就能提高查询速度,也有人感到迷惑:如果把复合的聚集索引字段分开查询,那么查询速度会减慢吗?带着这个问题,我们来看一下以下的查询速度(结果集都是25万条数据):(日期列fariqi首先排在复合聚集索引的起始列,用户名neibuyonghu排在后列):

  (1)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>''2004-5-5''

  
查询速度:2513毫秒

  (2)select gid,fariqi,neibuyonghu,title from Tgongwen
            where fariqi>''2004-5-5'' and neibuyonghu=''办公室''

  
查询速度:2516毫秒

  (3)select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu=''办公室''

  
查询速度:60280毫秒

  从以上试验中,我们可以看到如果仅用聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一样的,甚至比用上全部的复合索引列还要略快(在查询结果集数目一样的情况下);而如果仅用复合聚集索引的非起始列作为查询条件的话,这个索引是不起任何作用的。当然,语句1、2的查询速度一样是因为查询的条目数一样,如果复合索引的所有列都用上,而且查询结果少的话,这样就会形成“索引覆盖”,因而性能可以达到最优。同时,请记住:无论您是否经常使用聚合索引的其他列,但其前导列一定要是使用最频繁的列。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
发表于 2007-9-20 10:17:34 | 只看该作者
高人呀!
回复 支持 反对

使用道具 举报

该用户从未签到

3#
发表于 2011-2-21 14:32:55 | 只看该作者
茅塞顿开···
回复 支持 反对

使用道具 举报

该用户从未签到

4#
发表于 2011-3-14 15:12:30 | 只看该作者
不错,有点启发
回复 支持 反对

使用道具 举报

该用户从未签到

5#
发表于 2011-7-9 11:04:20 | 只看该作者
第一个讲得很不错,启发很大。3Q,另外补充点,由于创建索引会增加额外空间使用,所以创建时应该慎重,而且对于经常更新的记录,不应该在其上创建索引,因为在修改记录时,数据库也会对索引进行维护,会影响性能,所以即使创建了索引,也应该定期对索引进行维护,以保证索引高效性。另外还有各种索引适用点也不同,要理解各种索引的适用范围后,选择合适的索引,否则也仅会增加数据库负担而不会增加查询速度。献丑了……
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-25 03:44 , Processed in 0.068484 second(s), 27 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表