版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
常用SQL语句书写技巧SQL结构化查询字符串的改写,是实现数据库查询性能提升的最现实、最有效的手段,有时甚至是唯一的手段,比如在不允许大幅度修改现有数据库结构的情况下。通过优化SQL语句提高查询性能的关键是:根据实际需求情况,建立合适的索引;使用一切可能的方式去利用好索引,避免全表扫描;尽量减少内存及数据I/O方面的开销建立索引(一)建立“适当”的索引,是快速查询的基础。 索引(index)是除表之外另一重要的、用户定义的存储在物理介质上的数据结构。当根据索引码的值搜索数据时,索引提供了对数据的快速访问。事实上,没有索引,数据库也能根据SELECT语句成功地检索到结果,但随着表变得越来越大,使用“适当”的索引的效果就越来越明显。注意,在这句话中,我们用了“适当”这个词,这是因为,如果使用索引时不认真考虑其实现过程,索引既可以提高也会破坏数据库的工作性能。 索引实际上是一种特殊的目录,SQLSERVER提供了两种索引:聚集索引(clusteredindex,也称聚类索引、簇集索引)我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。例如:
汉语字典中按拼音查某一个字,就是使用“聚集索引”,实际上,你根本用不着查目录,直接在字典正文里找,就能很快找到需要的汉字(假设你知道发音)。非聚集索引(nonclusteredindex,也称非聚类索引、非簇集索引)我们把目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。例如:
汉语字典中按部首查某一个字,部首目录和正文一定要刻意的通过页码才能联系到一起,其顺序不是天然一致的。聚集索引与非聚集索引的最大区别就在于:聚集索引是对原数据表进行排序,因此只要符合索引条件,就能够直接连续的读取数据记录,几乎可以达到对数据表的零扫描;而非聚集索引仅仅只是另外建了一张索引表,取数据的时候,从索引表取得结果后,还需要到指针所指的数据行读取相应数据,因此,在性能上,聚集索引会大大优于非聚集索引。
但是在一张表中,聚集索引只允许一个,是比较宝贵的,因此要尽可能的用于那些使用频率最高的索引上。另外,查询时必需要用到索引的起始列,否则索引无效。另外,起始列也必需是使用频繁的列,那样的索引性能才会达到最优化。(二)表:何时应使用聚集索引或非聚集索引动作描述使用聚集索引使用非聚集索引列经常被分组排序○○返回某范围内的数据○一个或极少不同值小数目的不同值○大数目的不同值○频繁更新的列○外键列○○主键列○○频繁修改索引列○(三)索引建立的一些注意项1、不要把聚集索引浪费在主键上,除非你只按主键查询虽然SQLSERVER默认是在主键上建立聚集索引的,但实际应用中,这样做比较浪费。通常,我们会在每个表中都建立一个ID列,以区分每条数据,并且这个ID列是自动增大的,步长一般为1。此时,如果我们将这个列设为主键,SQLSERVER会将此列默认为聚集索引。这样做有好处,就是可以让您的数据在数据库中按照ID进行物理排序,但这样做实用价值不大。从我们前面谈到的聚集索引的定义我们可以看出,使用聚集索引的最大好处就是能够根据查询要求,迅速缩小查询范围,避免全表扫描。在实际应用中,因为ID号是自动生成的,我们并不知道每条记录的ID号,所以我们很难在实践中用ID号来进行查询。这就使让ID号这个主键作为聚集索引成为一种资源浪费。聚集索引相对与非聚集索引的优势是很明显的,而每个表中只能有一个聚集索引的规则,这使得聚集索引变得更加宝贵,应该用在其他查询频率高的字段上。其次,让每个ID号都不同的字段作为聚集索引也不符合“大数目的不同值情况下不应建立聚合索引”规则;当然,这种情况只是针对用户经常修改记录内容,特别是索引项的时候会负作用,但对于查询速度并没有影响。2、索引的建立要根据实际应用需求来进行并非是在任何字段上简单地建立索引就能提高查询速度。聚集索引建立的规则大致是“既不能绝大多数都相同,又不能只有极少数相同”。举个例子,在公文表的收发日期字段上建立聚合索引是比较合适的。在政务系统中,我们每天都会收一些文件,这些文件的发文日期将会相同,在发文日期上建立聚合索引对性能的提升应该是相当大的。在群集索引下,数据物理上按顺序存于数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。另一个相反的例子:比如在雇员表的“性别”列上只有“男”与“女”两个不同值,因此就完全没必要建立索引。3、在聚集索引中加入所有需要提高查询速度的字段,形成复合索引根据一些实验的结果,我们可以得出一些可供参考的结论:仅用复合聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询,速度是几乎一样的,甚至比后者还要快(在查询结果集数目一样的情况下);仅用复合聚集索引的非起始列作为查询条件的话,
这个索引是不起任何作用的。复合聚集索引的所有列都用上,而且因为查询条件严格,查询结果少的话,会形成“索引覆盖”,性能可以达到最优。最重要的一点:无论是否经常使用复合聚合索引的其他列,其起始列一定要是使用最频繁的列。4.根据实践得出的一些其他经验,特定情况下有效用聚合索引比用不是聚合索引的主键速度快;用聚合索引比用一般的主键作orderby速度快,特别是在小数据量情况;使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个;日期列不会因为有分秒的输入而减慢查询速度;由于改变一个表的内容,将会引起索引的变化。频繁的insert,update,delete语句将导致系统花费较大的代价进行索引更新,引起整体性能的下降。一般来讲,在对查询性能的要求高于对数据维护性能要求时,应该尽量使用索引,否则,就要慎重考虑一下付出的代价。在某些极端情况下,可先删除索引,再对数据库表更新大量数据,最后再重建索引,新建立的索引总是比较好用。编写优化的SQL语句,充分利用索引下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。SQL语句在提交给数据库进行操作前,都会经过查询分析阶段,SQLSERVER内置的查询优化器会分析查询条件的的每个部分,并判断这些条件是否符合扫描参数(SARG)的标准。只有当一个查询条件符合SARG的标准,才可以通过预先设置的索引,提升查询性能。SARG的定义:用于限制搜索操作的一种规范,通常是指一个特定的匹配,一个确定范围内的匹配或者两个以上条件的AND连接。一般形式如下:列名操作符<常数或变量>或<常数或变量>操作符列名列名可以出现在操作符的一边,而常数或变量出现在操作符的另一边。如:Name=’张三’价格>50005000<价格Name=’张三’and价格>5000如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是说SQLSERVER必须对每一行都判断它是否满足WHERE子句中的所有条件,既进行全表扫描。所以,一个索引对于不满足SARG形式的表达式来说是无用的,如:当查询条件为“价格*2>5000”时,就无法利用建立在价格字段上的SQLSERVER内置了查询优化器,能将一些条件自动转换为符合SARG标准,如:将“价格*2>5000”转换为“价格>2500/2”,以达到可以使用索引的目的,但这种转化不是100%可靠的,有时会有语义上的损失,有时转化不了。如果对“查询优化器”的工作原理不是特别了解,写出的SQL语句可能不会按照您的本意进行查询。所以不能完全依赖查询优化器的优化,建议大家还是利用自己的优化知识,尽可能显式的书写出符合SARG标准的SQL语句,自行确定查询条件的构建方式,这样一方面有利于查询分析器分析最佳索引匹配顺序,另一方面也有利介绍完SARG后,我们再结合一些实际运用中的例子来做进一步的讲解:Like语句是否属于SARG取决于使用%通配符的样式如:namelike‘张%’,这就属于SARG而:namelike‘%张’,就不属于SARG通配符%在字符串首字符的使用会导致索引无法使用,虽然实际应用中很难避免这样用,但还是应该对这种现象有所了解,至少知道此种用法性能是很低下的。“非”操作符不满足SARG形式,使得索引无法使用不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOTEXISTS、NOTIN、NOTLIKE等。下面是一个NOT子句的例子:
...wherenot(status='valid')
not运算符也隐式的包含在另外一些逻辑运算符中,比如<>运算符。见下例:
...wherestatus<>'invalid';
再看下面这个例子:
select*fromemployeewheresalary<>3000;
对这个查询,可以改写为不使用not:
select*fromemployeewheresalary<3000orsalary>3000;
虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许对salary列使用索引,而第一种查询则不能使用索引。函数运算不满足SARG形式,使得索引无法使用例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:select*fromrecordwheresubstring(card_no,1,4)=′5378′(13秒)select*fromrecordwhereamount/30<1000(11秒)select*fromrecordwhereconvert(char(10),date,112)=′19991201′(10秒)分析:
where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行全表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:select*fromrecordwherecard_nolike′5378%′(<1秒)select*fromrecordwhereamount<1000*30(<1秒)select*fromrecordwheredate=′1999/12/01′(<1秒)你会发现SQL明显快很多尽量不要对建立了索引的字段,作任何的直接处理select*fromemployswherefirst_name+last_name='beillcliton';
无法使用索引改为:select*fromemployeewherefirst_name=substr('beillcliton',1,instr('beillcliton','')-1)andlast_name=substr('beillcliton',instr('beillcliton','')+1)
则可以使用索引不同类型的索引效能是不一样的,应尽可能先使用效能高的比如:数字类型的索引查找效率高于字符串类型,定长字符串char,nchar的索引效率高于变长字符串varchar,nvarchar的索引。应该将whereusername='张三'andage>20改进为whereage>20andusername='张三'注意:此处,SQL的查询分析优化功能可以做到自动重排条件顺序,但还是建议预先手工排列好。尽量不要使用isnull与isnotnull作为查询条件任何包含null值的列都将不会被包含在索引中,如果某列数据中存在空值,那么对该列建立索引的性能提升是值得怀疑的,尤其是将null作为查询条件的一部分时。建议一方面避免使用isnull和isnotnull,另一方面不要让数据库字段中存在null,即使没有内容,也应利用缺省值,或者手动的填入一个值,如:’’空字符串。
某些情况下IN的作用与OR相当,且都不能充分利用索引例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:selectcount(*)fromstuffwhereid_noin(′0′,′1′)(23秒)
where条件中的′in′在逻辑上相当于′or′,所以语法分析器会将in(′0′,′1′)转化为id_no=′0′orid_no=′1′来执行。我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;但实际上,它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。
实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间会非常长!如果确定不同的条件不会产生大量重复值,还不如将or子句分开:
selectcount(*)fromstuffwhereid_no=′0′ selectcount(*)fromstuffwhereid_no=′1′得到两个结果,再用union作一次加法合算。因为每句都使用了索引,执行时间会比较短, selectcount(*)fromstuffwhereid_no=′0′ union selectcount(*)fromstuffwhereid_no=′1′从实践效果来看,使用union在通常情况下比用or的效率要高的多,而exist关键字和in关键字在用法上类似,性能上也类似,都会产生全表扫描,效率比较低下,根据未经验证的说法,exist可能比in要快些。使用变通的方法提高查询效率like关键字支持通配符匹配,但这种匹配特别耗时。例如:select*fromcustomerwherezipcodelike“21___”,即使在zipcode字段上已建立了索引,在这种情况下也可能还是采用全表扫描方式。如果把语句改为:select*fromcustomerwherezipcode>“21000”,在执行查询时就会利用索引,大大提高速度。但这种变通是有限制的,不应引起业务意义上的损失,对于邮政编码而言,zipcodelike“21___”和zipcode>“21000”组合索引的高效使用假设已在date,place,amount三个字段上建立了组合索引selectcount(*)fromrecord
wheredate>′19991201′anddate<′19991214′andamount>2000 (<1秒)selectdate,sum(amount)fromrecordgroupbydate(11秒)selectcount(*)fromrecord
wheredate>′19990901′andplacein(′BJ′,′SH′)(<1秒)
这是一个设置较合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。如果索引不便于更改,修正SQL中的条件顺序以配合索引顺序也是可行的。orderby按聚集索引列排序效率最高排序是较耗时的操作,应尽量简化或避免对大型表进行排序,如缩小排序的列的范围,只在有索引的列上排序等等。我们来看:(gid是主键,fariqi是聚合索引列)selecttop10000gid,fariqi,reader,titlefromtgongwen用时:196毫秒。扫描计数1,逻辑读289次,物理读1次,预读1527次。selecttop10000gid,fariqi,reader,titlefromtgongwenorderbygidasc用时:4720毫秒。扫描计数1,逻辑读41956次,物理读0次,预读1287次。selecttop10000gid,fariqi,reader,titlefromtgongwenorderbygiddesc用时:4736毫秒。扫描计数1,逻辑读55350次,物理读10次,预读775次。selecttop10000gid,fariqi,reader,titlefromtgongwenorderbyfariqiasc用时:173毫秒。扫描计数1,逻辑读290次,物理读0次,预读0次。selecttop10000gid,fariqi,reader,titlefromtgongwenorderbyfariqidesc用时:156毫秒。扫描计数1,逻辑读289次,物理读0次,预读0次。从以上我们可以看出,不排序的速度以及逻辑读次数都是和“orderby聚集索引列”的速度是相当的,但这些都比“orderby非聚集索引列”的查询速度是快得多的。同时,按照某个字段进行排序的时候,无论是正序还是倒序,速度是基本相当的。关于节省数据查询系统开销方面的措施使用TOP尽量减少取出的数据量TOP是SQLSERVER中用来提取前几条或前某个百分比数据的关键词。
selecttop20gid,fariqi,reader,titlefromtgongwenorderbygiddesc
selecttop60percentgid,fariqi,reader,titlefromtgongwenorderbygiddesc在实际的应用中,应该经常利用top剔除掉不必要的数据,只保留必须的数据集合。这样不仅可以减少数据库逻辑读的次数,还能避免不必要的内存浪费,对系统性能的提升都是有好处的。字段提取要按照“需多少、提多少”的原则,避免“select*”这个举个例子:selecttop10000gid,fariqi,reader,titlefromtgongwenorderbygiddesc用时:4673毫秒selecttop10000gid,fariqi,titlefromtgongwenorderbygiddesc用时:1376毫秒selecttop10000gid,fariqifromtgongwenorderbygiddesc用时:80毫秒由此看来,字段大小越大,数目越多,select所耗费的资源就越多,比如取int类型的字段就会比取char的快很多。我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的幅度根据舍弃的字段的大小来判断。count(*)与count(字段)方法比较我们来看一些实验例子(gid为Tgongwen的主键):selectcount(*)fromTgongwen用时:1500毫秒selectcount(gid)fromTgongwen用时:1483毫秒selectcount(fariqi)fromTgongwen用时:3140毫秒selectcount(title)fromTgongwen用时:52050毫秒从以上可以看出,用count(*)和用count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总速度就越慢。如果用count(*),SQLSERVER会自动查找最小字段来汇总。当然,如果您直接写count(主键)将会来的更直接些。有嵌套查询时,尽可能在内层过滤掉数据如果一个列同时在主查询和where子句中出现,很可能当主查询中的列值改变之后,子查询必须重新查询一次。而且查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行。
多表关联查询时,需注意表顺序,并尽可能早的过滤掉数据在使用Join进行多表关联查询时候,应该使用系统开销最小的方案。连接条件要充份考虑带有索引的表、行数多的表,并注意优化表顺序;说的简单一点,就是尽可能早的将之后要做关联的数据量降下来。一般情况下,sqlserver会对表的连接作出自动优化。例如:selectname,nofromAjoinBonA.id=B.idjoinConC.id=
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024至2030年中国口腔内窥镜四分割处理器数据监测研究报告
- 高频接收机课程设计
- 清明实践课程设计
- 2024年中国须膏市场调查研究报告
- 中国茶胺酸行业产销需求及前景动态预测研究报告(2024-2030版)
- 中国聚乙烯催化剂行业发展状况及需求规模预测研究报告(2024-2030版)
- 生物竞赛 课程设计理念
- 中国笔制造行业发展前景与趋势预测分析研究报告(2024-2030版)
- 中国白油行业销售状况与应用前景预测研究报告(2024-2030版)
- 中国玻璃钢化粪池行业市场现状分析及竞争格局与投资发展研究报告(2024-2030版)
- 江苏省南通市市区2023-2024学年五年级上学期期中数学试卷
- 2024年济南轨道交通集团限公司招考(75名)易考易错模拟试题(共500题)试卷后附参考答案
- 计算机应用基础
- 第五单元 倍的认识(单元测试)-2024-2025学年三年级上册数学人教版
- 按键外观及可靠性测试检验标准
- 安防监控系统室外施工安装规范标准
- 胸痛鉴别诊断
- 元明粉比重表
- 房地产估价理论与方法重要公式整理
- 房地产项目投资成本测算参考表
- 提高护士对抢救药品知晓率PDCA案例精编版
评论
0/150
提交评论