(一)深入浅出理解索引结æž?nbsp;
实际上,您可以把索引理解为一种特殊的ç›?½•。微è½?š„SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引ã?�簇集索引)和非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)ã?‚下é�?¼Œ我们举例来è?明一下聚集索引和非聚集索引的区别ï¼?nbsp;
其实,我ä»?š„汉è?字典的æ?文本èº?°±æ˜?¸€ä¸?�š集索引ã?‚比如,我们要查“安”字,就会很è‡?„¶地翻å¼?字典的前几页,因为â?œ安”的拼音æ˜??œan”,而按照拼音排序汉字的字典æ˜?»¥英文字母“a”开头并以â?œz”结尾的,那么â?œ安”字就自然地排在字典的前部ã?‚å?果您翻完了所有以“a”开头的部分仍然找不到这ä¸?—,那么就说明您的字典ä¸?²¡有这ä¸?—;同样的,å?果查“张”字,那您也会将您的字典翻到æœ?后部分,因为“张”的拼音æ˜??œzhang”ã?‚也就是说,字典的æ?文部分本èº?°±æ˜?¸€ä¸?›®录,您不éœ?要再去查其他ç›?½•来找到您éœ?要找的内容ã??nbsp;
我们把这种æ?文内容本èº?°±æ˜?¸€种按照一定è?则排列的ç›?½•称为“聚集索引â?�ã??nbsp;
如果您è?识某ä¸?—,您å�?»¥å¿??Ÿ地从自动中查到这个字ã?‚但您也å�?ƒ½会遇到您不è?识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,è?Œ需要去根据“偏旁部首â?�查到您要找的字,然后根æ�?¿™ä¸?—后的页码直接翻到某页来找到您要找的字。但您结合â?œ部首目录â?�和“æ?字表”è?Œ查到的字的排序并不æ˜?œŸ正的正文的排序方法,比å?您查“张”字,我ä»?�¯以看到在查部首之后的æ£?字表ä¸??œ张”的页码æ˜?72页,æ£?字表ä¸??œ张”的上面æ˜??œ驰”字,但页码却是63页,“张”的下面æ˜??œ弩”字,页面是390页ã?‚很显然,这些字并不æ˜?œŸ正的分别位于“张”字的上下方,现在您看到的连ç»?š„“驰、张、弩”三字实际上就是他们在非聚集索引ä¸?š„排序,是字典正文ä¸?š„字在非聚集索引中的映射ã?‚我ä»?�¯以é?š过这ç?方式来找到您æ‰?éœ?要的字,但它éœ?要两ä¸?¿‡程,先找到目录中的结果,然后再翻到您æ‰?éœ?要的页码ã€?nbsp;
我们把这种目录纯粹是ç›?½•,æ?文纯粹是正文的排序方式称为â?œ非聚集索引”ã??nbsp;
通过以上例子,我ä»?�¯以理解到ä»?么是“聚集索引â?�和“非聚集索引”ã??nbsp;
进一步引申一下,我们å�?»¥很å?易的理解:每ä¸?¡¨å�?ƒ½有一ä¸?�š集索引,因为ç›?½•å�?ƒ½按照ä¸?种方法进行排序ã??nbsp;
(二)何时使用聚集索引或非聚集索å¼?nbsp;
下面的表总结了何时使用聚集索引或非聚集索引(很重要)ã€?nbsp;

事实上,我们å�?»¥通过前面聚集索引和非聚集索引的定义的例子来理解上表ã?‚å?:返回某范围内的数据ä¸?项ã?‚比如您的某ä¸?¡¨有一ä¸?—¶间列,恰好您把聚合索引建立在了è?列,这时您查è¯?004å¹?æœ?日至2004å¹?0æœ?日之间的全部数据时,这个速度就将æ˜?¾ˆå¿?š„,因为您的这æœ?—典æ?文是按日期进行排序的,聚类索引只éœ?要找到è?æ£?索的æ‰?有数æ�?¸的开头和结尾数据即可;è?Œ不像非聚集索引,必须先查到ç›?½•ä¸?Ÿ¥到每ä¸?项数æ�??应的页码,然后再根据页码查到具体内å?ã€?nbsp;
(三)结合实际,谈索引使用的è¯?Œº
理è?的目的是应用。虽然我ä»?ˆš才列出了何时应使用聚集索引或非聚集索引,但在实践ä¸?»¥上è?则却很å?易è?忽è?或不能根æ�?®ž际情况进行综合分析ã?‚下面我ä»?°†根据在实践中遇到的实际问题来谈一下索引使用的è¯?Œº,以便于大å?掌握索引建立的方法ã??nbsp;
1、主é”?°±æ˜?�š集索å¼?nbsp;
这ç?想法笔è?…è?为是极ç?错è?的,æ˜??聚集索引的一种浪费ã?‚虽然SQL SERVER默è?æ˜?œ¨主键上建立聚集索引的ã€?nbsp;
通常,我ä»?¼š在每ä¸?¡¨ä¸?ƒ½建立ä¸?个ID列,以区分每条数æ�?¼Œ并且这个ID列是è‡?Ѝ增大的,步长ä¸?èˆ?¸º1。我ä»?š„这个办公è‡?Ѝ化的实例ä¸?š„列Gid就是如æ?。æ?时,如果我们将这ä¸?ˆ—设为主键,SQL SERVER会将此列默è?为聚集索引ã?‚这样做有好处,就是å�?»¥让您的数æ�?œ¨数据库中按照ID进è?物理排序,但笔è?…è?为这样做意义不大ã€?nbsp;
显è?Œ易见,聚集索引的优势是很明显的,è?Œ每ä¸?¡¨ä¸?�ª能有ä¸?ä¸?�š集索引的规则,这使得聚集索引变得更加珍贵ã€?nbsp;
从我ä»?‰�面谈到的聚集索引的定义我ä»?�¯以看出,使用聚集索引的最大好处就æ˜?ƒ½够根æ�?Ÿ¥询è?求,迅é?Ÿ缩小查询范围,避免全表æ‰?��。在实际应用ä¸?¼Œ因为ID号是è‡?Ѝ生成的,我们并不知道每条记录的ID号,æ‰?以我ä»?¾ˆ难在实践ä¸?”¨ID号来进è?查è?。这就使让ID号这ä¸?¸»é”?½œ为聚集索引成为一种资源浪费ã?‚其次,让每个ID号都不同的字段作为聚集索引也不ç?合â?œ大数目的不同å?¼情况下不应建立聚合索引”è?则;当然,这种情况只æ˜?’ˆ对用户经常修改è?录内容,特别æ˜?´¢引项的时候会负作ç”?¼Œ但å?于查询é?Ÿ度并没有影响ã??nbsp;
在办å…?‡ª动化系统ä¸?¼Œ无è?æ˜?³»统é?页显示的éœ?要用户ç?收的文件、会è®?¿˜æ˜?”¨户进行文件查询等任何情况下进行数æ�?Ÿ¥询都离不å¼?字æ?的是“日期â?�还有用户本èº?š„“用户名”ã??nbsp;
通常,办å…?‡ª动化的é?页会显示每个用户尚未签收的文件或会è?。虽然我ä»?š„whereè¯?�¥å�?»¥仅仅限制当前用户尚未签收的情况,但å?果您的系统已建立了很长时间,并且数据量很大,那么,每次每ä¸?”¨户打å¼?首页的时候都进è?ä¸?次全表扫描,这样做意义是不大的,绝大多数的用æˆ?ä¸?œˆ前的文件都已经浏览过了,这样做只能徒增数æ�?º“的开é”?而已。事实上,我ä»?®Œ全可以è?用户打开系统首页时,数据库仅仅查询这ä¸?”¨户近3ä¸?œˆ来未阅è?的文件,通过“日期â?�这ä¸?—段来限制表扫描,提高查è?速度。å?果您的办å…?‡ª动化系统已经建立çš?年,那么您的首页显示速度理è?上将æ˜?ŽŸ来é?Ÿ度8倍,甚至更快ã€?
在这里之æ‰?以提到â?œ理论上”三字,æ˜?› 为å?果您的聚集索引还æ˜?›²ç›?œ°建在ID这个主键上时,您的查询é?Ÿ度æ˜?²¡有这么高的,即使您在“日期â?�这ä¸?—段上建立的索引(非聚合索引)。下面我ä»?°±来看ä¸?下在1000万条数据量的情况下各种查询的速度表现ï¼?ä¸?œˆ内的数据ä¸?5万条):
ï¼?)仅在主é”?¸Š建立聚集索引,并且不划分时间段:
Select gid,fariqi,neibuyonghu,title from tgongwen
用时ï¼?28470æ¯??(即ï¼?28秒)
ï¼?)在主键上建立聚集索引,在fariq上建立非聚集索引ï¼?nbsp;
select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi> dateadd(day,-90,getdate())
用时ï¼?3763æ¯??ï¼?4秒)
ï¼?)将聚合索引建立在日期列(fariqi)上ï¼?nbsp;
select gid,fariqi,neibuyonghu,title from Tgongwen
where fariqi> dateadd(day,-90,getdate())
用时ï¼?423æ¯??ï¼?秒)
虽然每条è¯?�¥提取出来的都æ˜?5万条数据,各种情况的å·?¼‚却是巨大的,特别æ˜?°†聚集索引建立在日期列时的å·?¼‚。事实上,å?果您的数æ�?º“真的æœ?000万å?量的话,把主é”?»º立在ID列上,就像以上的ç¬?ã€?种情况,在网页上的表现就æ˜?¶…时,根本就无法显示ã?‚这也是我摒弃ID列作为聚集索引的ä¸?ä¸?œ€重è?的因素ã??nbsp;
得出以上速度的方法是:在各个selectè¯?�¥前加:declare @d datetime
set @d=getdate()
并在selectè¯?�¥后加ï¼?nbsp;
select [è¯?�¥执è?花费时间(æ¯??)]=datediff(ms,@d,getdate())
2、只要建立索引就能显著提高查询é?Ÿ度
事实上,我们å�?»¥发现上面的例子中,ç?2ã€?条è?句完全相同,且建立索引的字æ?也相同;不同的仅æ˜?‰�者在fariqi字æ?上建立的æ˜?�ž聚合索引,后者在此字段上建立的是聚合索引,但查è?速度却有ç�?天壤之别。所以,并非æ˜?œ¨任何字æ?上简单地建立索引就能提高查è?速度ã€?nbsp;
从建表的è¯?�¥ä¸?¼Œ我们å�?»¥看到这个有着1000万数æ�?š„表中fariqi字æ?æœ?003ä¸?¸�同è?录ã?‚在此字段上建立聚合索引æ˜?†�合é?‚不过了。在现实ä¸?¼Œ我们每天都会发几ä¸?–‡件,这几ä¸?–‡件的发文日期就相同,这完全ç?合建立聚集索引è?求的:â?œ既不能绝大多数都相同,又不能只有极少数相同”的规则。由此看来,我们建立“é?‚当”的聚合索引对于我们提高查è?速度æ˜?�ž常重要的ã€?nbsp;
3、把æ‰?有需要提高查询é?Ÿ度的字段都加进聚集索引,以提高查è?速度
上面已经谈到:在进è?数据查è?时都离不å¼?字æ?的是“日期â?�还有用户本èº?š„“用户名”ã?‚既然这两个字æ?都是如æ?的重要,我们å�?»¥把他ä»?�ˆ并起来,建立ä¸?ä¸??合索引(compound index)ã??nbsp;
很å?人è?为只要把任何字æ?加进聚集索引,就能提高查询é?Ÿ度,也有人感到迷惑:å?果把复合的聚集索引字段分å¼?查è?,那么查询é?Ÿ度会减慢吗?带ç�?这个é—??,我ä»?�¥看一下以下的查è?速度(结果集都是25万条数据):(日期列fariqi首先排在复合聚集索引的起始列,用户名neibuyonghu排在后列ï¼?nbsp;
ï¼?)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5'
查è?速度ï¼?513æ¯??
ï¼?)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5' and neibuyonghu='办公å®?
查è?速度ï¼?516æ¯??
ï¼?)select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu='办公å®?
查è?速度ï¼?0280æ¯??
从以上试验中,我ä»?�¯以看到å?果仅用聚集索引的起å?列作为查询条件和同时用到复合聚集索引的全部列的查询é?Ÿ度æ˜?‡ 乎一样的,甚至比用上全部的å?合索引列还è?略快(在查è?结果集数ç›?¸€样的情况下);è?Œå?果仅用å?合聚集索引的非起始列作为查è?条件的话,这ä¸?´¢引是不起任何作用的ã?‚当然,è¯?�¥1ã€?的查询é?Ÿ度ä¸?样是因为查è?的条ç›?•°ä¸?样,如果复合索引的所有列都用上,而且查è?结果少的话,这样就会形成“索引è?盖â?�,因è?Œæ?§能å�?»¥达到æœ?优ã?‚同时,请è?住:无è?您是否经常使用聚合索引的其他列,但其前å?列一定è?æ˜?½¿用最频繁的列ã€?nbsp;
(四)其他书上没有的索引使用经验总结
1、用聚合索引比用不是聚合索引的主é”??Ÿ度å¿?nbsp;
下面æ˜?®ž例è?句:(都æ˜?��å�?5万条数据ï¼?nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'
使用时间ï¼?326æ¯??
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000
使用时间ï¼?470æ¯??
这里,用聚合索引比用不是聚合索引的主é”??Ÿ度å¿?º†è¿?/4ã€?nbsp;
2、用聚合索引比用ä¸?èˆ?š„主键作order by时é?Ÿ度å¿?¼Œ特别æ˜?œ¨小数æ�?‡�情况ä¸?nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi
用时ï¼?2936
select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid
用时ï¼?8843
这里,用聚合索引比用ä¸?èˆ?š„主键作order by时,速度å¿?º†3/10。事实上,å?果数æ�?‡�很小的话,用聚集索引作为排序列è?比使用非聚集索引速度å¿?¾—明显的å?;è?Œ数æ�?‡�如果很大的话,å?10万以上,则二者的速度å·?ˆ«不明显ã??nbsp;
3、使用聚合索引内的时间æ?,搜索时间会按数æ�?� 整个数据表的百分比成比例减少,è?Œ无论聚合索引使用了多少ä¸?nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1'
用时ï¼?343æ¯??(提å�?00万条ï¼?nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-6-6'
用时ï¼?170æ¯??(提å�?0万条ï¼?nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'
用时ï¼?326æ¯??(和上句的结果一模一样ã?‚å?果采集的数量ä¸?样,那么用大于号和等于号æ˜?¸€样的ï¼?nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' and fariqi<'2004-6-6'
用时ï¼?280æ¯??
4 、日期列不会因为有分秒的输入而减慢查询é?Ÿ度
下面的例子中,共æœ?00万条数据ï¼?004å¹?æœ?日以后的数据æœ?0万条,但å�?œ‰两个不同的日期,日期精确到日;之前有数据50万条,有5000ä¸?¸�同的日期,日期精ç¡?ˆ°秒ã??nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' order by fariqi
用时ï¼?390æ¯??
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi<'2004-1-1' order by fariqi
用时ï¼?453æ¯??
(五)其他注意事é¡?nbsp;
“水å�?½½舟,亦可覆舟”,索引也一样ã?‚索引有助于提高æ£?索æ?§能,但过å?或不当的索引也会导致系统低效。因为用户在表中每加进一ä¸?´¢引,数据库就要做更å?的工作ã?‚过多的索引甚至会å?致索引ç?片ã??nbsp;
æ‰?以è?,我ä»??建立ä¸?ä¸??œé?‚当”的索引体系,特åˆ?˜¯对聚合索引的创建,更应精益求精,以使您的数据库能得到高æ?§能的发挥ã??nbsp;
当然,在实践ä¸?¼Œ作为ä¸?ä¸?°½职的数据库ç?理员,您还è?多测试一些方案,找出å“??方æ?效率æœ?高ã?�最为有效ã??nbsp;
二ã?�改善SQLè¯?�¥
很å?人不知道SQLè¯?�¥在SQL SERVERä¸?˜¯如何执è?的,他们担心è‡?·±æ‰?写的SQLè¯?�¥会è?SQL SERVERè¯?§£。比如:
select * from table1 where name='zhangsan' and tID > 10000
和执è¡?
select * from table1 where tID > 10000 and name='zhangsan'
ä¸?些人不知道以上两条è?句的执è?效率æ˜?�¦ä¸?样,因为如果ç®?单的从è?句先后上看,这两ä¸??句的ç¡?˜¯不一样,如果tIDæ˜?¸€ä¸?�š合索引,那么后一句仅仅从表的10000条以后的记录ä¸?Ÿ¥找就行了;è?Œ前ä¸?句则要先从全表中查找看有几个name='zhangsan'的,而后再根æ�?™�制条件条件tID>10000来提出查询结果ã??nbsp;
事实上,这样的担心是不必要的。SQL SERVERä¸?œ‰ä¸?ä¸??œ查询分析优化器”,它可以è?算出where子句ä¸?š„搜索条件并确定哪ä¸?´¢引能缩小表扫描的搜索空间,也就是说,它能实现è‡?Ѝ优化ã€?nbsp;
虽然查è?优化器可以根据where子句è‡?Ѝ的进行查è¯?¼˜化,但大家仍然有必è?了解ä¸?下â?œ查è¯?¼˜化器”的工作原理,å?非这样,有时查è?优化器就会不按照您的æœ?„�进è?å¿??Ÿ查è¯???nbsp;
在查询分析阶段,查è?优化器查看查询的每个阶æ?并决定限制需要扫描的数据量是否有用ã?‚å?果一ä¸?˜¶段可以è?用作ä¸?ä¸?‰«描参数(SARG),那么就称之为å�?¼˜化的,并且可以利用索引快速获得所éœ?数据ã€?nbsp;
SARG的定义:用于限制搜索的一ä¸?“�作,因为它é?š常æ˜?Œ‡ä¸?ä¸?‰¹定的匹配,一ä¸??¼得范围内的匹配或è?…两ä¸?»¥上条件的AND连接。形式å?下:
列名 操作ç¬?nbsp; <常数 æˆ?nbsp; 变量>
�nbsp;
<常数 æˆ?nbsp; 变量> 操作符列å�?nbsp;
列名å�?»¥出现在操作ç?的一边,而常数或变量出现在操作ç?的另ä¸?边ã?‚å?ï¼?nbsp;
Name=’张三â??nbsp;
价格>5000
5000<价格
Name=’张三â??nbsp; and 价格>5000
如果ä¸?ä¸?¡¨达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是SQL SERVER必须对每ä¸?行都判断它是否满足WHERE子句ä¸?š„æ‰?有条件ã?‚所以一ä¸?´¢引å?于不满足SARG形式的表达式来è?æ˜?— 用的ã€?nbsp;
介绍完SARG后,我们来æ?»结ä¸?下使用SARG以及在实践中遇到的和某些资料上结论不同的经验ï¼?nbsp;
1、Likeè¯?�¥æ˜?�¦属于SARG取决于所使用的é?š配符的类型
如:name like ‘张%â€?nbsp; ,这就属于SARG
而:name like â€?张â??nbsp; ,就不属于SARGã€?nbsp;
原因æ˜??š配ç¬?在字符串的开通使得索引无法使用ã??nbsp;
2、or 会引起全表扫æ�?nbsp;
Name=’张三â??nbsp; and 价格>5000 符号SARG,è?Œ:Name=’张三â??nbsp; or 价格>5000 则不符合SARG。使用or会引起全表扫描ã??nbsp;
、非操作符ã?�函数引起的不满足SARG形式的è?å�?nbsp;
不满足SARG形式的è?句最典型的情况就æ˜?Œ…æ‹?�ž操作符的è¯?�¥,å?:NOTã€?=ã€?lt;>ã€?<ã€?>、NOT EXISTS、NOT IN、NOT LIKE等,另å?还有函数。下面就æ˜?‡ ä¸?¸�满足SARG形式的例子:
ABS(价格)<5000
Name like â€?三â??nbsp;
有些表达式,如:
WHERE 价格*2>5000
SQL SERVER也会认为是SARG,SQL SERVER会将此式è½?Œ–为:
WHERE 价格>2500/2
但我ä»?¸�推荐这样使用,因为有时SQL SERVER不能保证这ç?è½?Œ–与原始表达式æ˜?®Œ全等价的ã€?nbsp;
4、IN 的作用相当与OR
è¯?�¥ï¼?nbsp;
Select * from table1 where tid in (2,3)
å’?nbsp;
Select * from table1 where tid=2 or tid=3
æ˜?¸€样的,都会引起全表扫描,如果tid上有索引,其索引也会失效ã€?nbsp;
5、尽量少用NOT
6、exists å’?nbsp; in 的执行效率是ä¸?样的
很å?资料上都显示说,exists要比in的执行效率è?高,同时应尽å�?ƒ½的用not exists来代替not in。但事实上,我试验了ä¸?下,发现二è?…无论是前面带不å¸?ot,二者之间的执è?效率都是ä¸?样的。因为涉及子查è?,我ä»?¯•验这次用SQL SERVERè‡?¸¦的pubs数据库ã?‚运行前我们å�?»¥把SQL SERVER的statistics I/O状æ?�打å¼?ã€?nbsp;
ï¼?)select title,price from titles where title_id in (select title_id from sales where qty>30)
该句的执行结果为ï¼?nbsp;
è¡?nbsp; 'sales'。扫描è?æ•?nbsp; 18,é?»辑è¯?nbsp; 56 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
è¡?nbsp; 'titles'。扫描è?æ•?nbsp; 1,é?»辑è¯?nbsp; 2 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
ï¼?)select title,price from titles where exists (select * from sales where sales.title_id=titles.title_id and qty>30)
ç¬?ºŒ句的执è?结果为:
è¡?nbsp; 'sales'。扫描è?æ•?nbsp; 18,é?»辑è¯?nbsp; 56 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
è¡?nbsp; 'titles'。扫描è?æ•?nbsp; 1,é?»辑è¯?nbsp; 2 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
我们从æ?å�?»¥看到用exists和用in的执行效率是ä¸?样的ã€?nbsp;
7、用函数charindex()和前面加通配ç¬?的LIKE执è?效率ä¸?æ ?nbsp;
前面,我ä»?°ˆ到,如果在LIKE前面加上通配ç¬?,那么将会引起全表扫描,æ‰?以其执è?效率æ˜?½Ž下的。但有的资料介绍说,用函数charindex()来代替LIKE速度会有大的提升,经我试验,发现这ç?说明也是错è?的:
select gid,title,fariqi,reader from tgongwen where charindex('刑侦æ”?˜Ÿ',reader)>0 and fariqi>'2004-5-5'
用时ï¼?秒,另å?:扫描è?æ•?nbsp; 4,é?»辑è¯?nbsp; 7155 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
select gid,title,fariqi,reader from tgongwen where reader like '%' + '刑侦æ”?˜Ÿ' + '%' and fariqi>'2004-5-5'
用时ï¼?秒,另å?:扫描è?æ•?nbsp; 4,é?»辑è¯?nbsp; 7155 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
8、union并不绝å?比or的执行效率高
我们前面已经谈到了在where子句ä¸?½¿用or会引起全表扫描,ä¸?èˆ?š„,我æ‰?见过的资料都æ˜?ލ荐这里用union来代替or。事实证明,这ç?说法对于大部分都æ˜??‚用的ã??nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or gid>9990000
用时ï¼?8秒ã?‚扫描è?æ•?nbsp; 1,é?»辑è¯?nbsp; 404008 次,物理è¯?nbsp; 283 次,预è? 392163 次ã??nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid>9990000
用时ï¼?秒ã?‚扫描è?æ•?nbsp; 8,é?»辑è¯?nbsp; 67489 次,物理è¯?nbsp; 216 次,预è? 7499 次ã??nbsp;
看来,用union在é?š常情况下比用or的效率è?高的多ã??nbsp;
但经过试验,笔è?…发现å?果or两边的查询列æ˜?¸€样的话,那么用union则反倒和用or的执行é?Ÿ度å·?¾ˆ多,虽然这里unionæ‰?��的是索引,è?Œoræ‰?��的是全表ã€?nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or fariqi='2004-2-5'
用时ï¼?423æ¯??。扫描è?æ•?nbsp; 2,é?»辑è¯?nbsp; 14726 次,物理è¯?nbsp; 1 次,预è? 7176 次ã??nbsp;
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-2-5'
用时ï¼?1640æ¯??。扫描è?æ•?nbsp; 8,é?»辑è¯?nbsp; 14806 次,物理è¯?nbsp; 108 次,预è? 1144 次ã??nbsp;
9、字段提取è?按照“需多少、提多少”的原则,避免â?œselect *â€?nbsp;
我们来做ä¸?ä¸?¯•验:
select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc
用时ï¼?673æ¯??
select top 10000 gid,fariqi,title from tgongwen order by gid desc
用时ï¼?376æ¯??
select top 10000 gid,fariqi from tgongwen order by gid desc
用时ï¼?0æ¯??
由æ?看来,我ä»?¯�少提取一ä¸?—段,数据的提取é?Ÿ度就会有相应的提升。提升的速度还è?看您舍弃的字段的大小来判æ–???nbsp;
10、count(*)不比count(字æ?)æ…?nbsp;
某些资料上è?:用*会统计所有列,显然è?比一ä¸?¸–界的列名效率低ã?‚这种è?法其实是没有根据的ã?‚我ä»?�¥看:
select count(*) from Tgongwen
用时ï¼?500æ¯??
select count(gid) from Tgongwen
用时ï¼?483æ¯??
select count(fariqi) from Tgongwen
用时ï¼?140æ¯??
select count(title) from Tgongwen
用时ï¼?2050æ¯??
从以上可以看出,如果用count(*)和用count(主键)的é?Ÿ度æ˜?›¸当的,è?Œcount(*)却比其他任何除主é”?»¥外的字æ?汇æ?»é?Ÿ度要快,è?Œ且字æ?越长,汇总的速度就越æ…??‚我想,如果用count(*)ï¼?nbsp; SQL SERVERå�?ƒ½会自动查找最小字段来汇æ?»的。当然,如果您直接写count(主键)将会来的更直接些ã€?nbsp;
11、order by按聚集索引列排序效率æœ?é«?nbsp;
我们来看:(gidæ˜?¸»é”?¼Œfariqiæ˜?�š合索引列ï¼?nbsp;
select top 10000 gid,fariqi,reader,title from tgongwen
用时ï¼?96 æ¯??ã€?nbsp; æ‰?��计数 1,é?»辑è¯?nbsp; 289 次,物理è¯?nbsp; 1 次,预è? 1527 次ã??nbsp;
select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc
用时ï¼?720æ¯??ã€?nbsp; æ‰?��计数 1,é?»辑è¯?nbsp; 41956 次,物理è¯?nbsp; 0 次,预è? 1287 次ã??nbsp;
select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc
用时ï¼?736æ¯??ã€?nbsp; æ‰?��计数 1,é?»辑è¯?nbsp; 55350 次,物理è¯?nbsp; 10 次,预è? 775 次ã??nbsp;
select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc
用时ï¼?73æ¯??ã€?nbsp; æ‰?��计数 1,é?»辑è¯?nbsp; 290 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc
用时ï¼?56æ¯??ã€?nbsp; æ‰?��计数 1,é?»辑è¯?nbsp; 289 次,物理è¯?nbsp; 0 次,预è? 0 次ã??nbsp;
从以上我ä»?�¯以看出,不排序的速度以及逻辑读æ?数都æ˜?’Œ“order by 聚集索引列â??nbsp; 的é?Ÿ度æ˜?›¸当的,但这些都比“order by 非聚集索引列”的查è?速度æ˜?¿«得å?的ã??nbsp;
同时,按照某ä¸?—段进行排序的时å?™,无è?æ˜??序还æ˜??’序,é?Ÿ度æ˜?Ÿºæœ?›¸当的ã€?nbsp;
12、高效的TOP
事实上,在查询和提取超大容量的数æ�?›†时,影响数据库响应时间的æœ?大因素不æ˜?•°æ�?Ÿ¥找,而是物理的I/0操作。å?ï¼?nbsp;
select top 10 * from (
select top 10000 gid,fariqi,title from tgongwen
where neibuyonghu='办公å®?
order by gid desc) as a
order by gid asc
这条è¯?�¥,从理è?上è?,整条è?句的执è?时间应è?比子句的执è?时间长,但事实相反ã?‚因为,子句执è?后返回的æ˜?0000条è?录,而整条è?句仅返回10条è?句,æ‰?以影响数æ�?º“响应时间æœ?大的因素æ˜?‰©理I/O操作。è?Œ限制物理I/O操作此å?的最有效方法之一就是使用TOP关键词了。TOP关键词是SQL SERVERä¸?»�过系统优化过的一ä¸?”¨来提取前几条或前几个百分比数æ�?š„词ã?‚经笔è?…在实践ä¸?š„应用,发现TOPç¡?®ž很好ç”?¼Œ效率也很高ã?‚但这个词在另å?ä¸?ä¸?¤§型数æ�?º“ORACLEä¸?�´没有,这不能说不æ˜?¸€ä¸?�—憾,虽然在ORACLEä¸?�¯以用其他方法(å?:rownumber)来解决。在以后的关于â?œ实现千万级数据的分页显示存储过程â?�的讨è?ä¸?¼Œ我们就将用到TOP这个关键词ã??nbsp;