µ±ǰλÖ㺠´úÂëÃÔ >> SQL >> SQLä¸?´¢引的原理һ
  Ïêϸ½â¾ö·½°¸

SQLä¸?´¢引的原理һ

Èȶȣº17328   ·¢²¼ʱ¼䣺2016-05-05 10:48:19.0
SQLä¸?´¢引的原理1
(一)深入浅出理解索引结æž?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; 
   
  Ïà¹ؽâ¾ö·½°¸