如何做SqlServer 数据查询优化!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何做SqlServer 数据查询优化!相关的知识,希望对你有一定的参考价值。

一、建立索引
二、建立存储过程
三、只查询您所需要的数据,不要把所有数据都查询出来,防止数据冗余。
四、对于大量及海量数据一般还要建立分区
参考技术A 有很多种优化,索引\分区是常用优化方法。 参考技术B 1、适当的建立索引
2、规范查询语句
3、sql语句中尽量用参数,以便使用计划
4、拆分表,表分区
参考技术C 影响查询效率的因素    
SQLServer处理查询计划的过程是这样的:在做完查询语句的词法、语法检查之后,将语句提交给SQLServer的查询优化器,查询优化器通过检查索引的存在性、有效性和基于列的统计数据来决定如何处理扫描、检索和连接,并生成若干执行计划,然后通过分析执行开销来评估每个执行计划,从中选出开销最小的执行计划,由预编译模块对语句进行处理并生成查询规划,然后在合适的时间提交给系统处理执行,最后将执行结果返回给用户。所以,SQLServer中影响查询效率的因素主要有以下几种:
  1.没有索引或者没有用到索引。索引是数据库中重要的数据结构,使用索引的目的是避免全表扫描,减少磁盘I/O,以加快查询速度。
  2.没有创建计算列导致查询不优化。
  3.查询出的数据量过大(可以采用多次查询,其他的方法降低数据量)。
  4.返回了不必要的行和列。
  5.查询语句不好,没有优化。其中包括:查询条件中操作符使用是否得当;查询条件中的数据类型是否兼容;对多个 表查询时,数据表的次序是否合理;多个选择条件查询时,选择条件的次序是否合理;是否合理安排联接选择运算等。

SQLServer数据查询优化方法
    3.1建立合适的索引  索引是数据库中重要的数据结构,它的根本目的就是为了提高查询效率。当根据索引码的值搜索数据时,索引提供了对数据的快速访问。事实上,没有索引,数据库也能根据SELECT语句成功地检索到结果,但随着表变得越来越大,使用“适当”的索引的效果就越来越明显。索引的使用要恰到好处,其使用原则有:
  (1)对于基本表,不宜建立过多的索引;
  (2)对于那些查询频度高,实时性要求高的数据一定要建立索引,而对于其他的数据不考虑建立索引;
  (3)在经常进行连接,但是没有指定为外键的列上建立索引;
  (4)在频繁进行排序或分组(即进行groupby或 orderby操作)的列上建立索引;
  (5)在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要建立索引。比如在雇员表的“性别”列上只有“男”与“女”两个不同值,因此就无必要建立索引。如果建立索引不但不会提高查询效率,反而会严重降低更新速度;
  (6)如果待排序的列有多个,可以在这些列上建立复合索引。  在SQLServer中,索引按索引表达式包含的列分为单列索引和复合索引。检查查询语句的where子句,因为这是优化器重要关注的地方。包含在where里面的每一列都是可能的侯选索引,为能达到最优的性能,例如:对于在where子句中给出了 column1这个列,下面的两个条件可以提高索引的优化查询性能!
第一:在表中的column1列上有一个单索引;
第二:在表中有多索引,但是 column1是第一个索引的列。避免定义多索引而column1是第二个或后面的索引,这样的索引不能优化服务器性能。例如:下面的例子用了pubs数据库。  SELECTau_id,au_lname,au_fname  FROMauthorsWHEREau_lname=’White’  按下面几个列上建立的索引将会是对优化器有用的索引  au_lname  au_lname,au_fname  而在下面几个列上建立的索引将不会对优化器起到好的作用  au_address  au_fname,au_lname  在SQLServer中,索引按存储结构分为聚簇索引和非聚簇索引。聚簇索引是按照定义数据列值的顺序在物理上对记录排序,在一个表上只能有一个聚簇索引,聚簇索引查询速度较快,但缺点是对表进行修改操作时速度较慢,因为为了保证表中记录的物理顺序与索引的顺序一致,必须将记录插入到数据页的相应位置,从而数据页中的数据必须重排。在下面的几个情况下,可以考虑用聚簇索引:
(1)某列包括的不同值的个数是有限的(但是不是极少的)。如顾客表的州名列有50个左右的不同州名的缩写值,可以使用聚簇索引。  
(2)对返回一定范围内值的列可以使用聚簇索引,如用between,>,>=,   Select*fromsaleswhereord_datebetween’5/1/93’and’6/1/93’  
(3)对查询时返回大量结果的列可以使用聚簇索引。  SELECT*FROMphonebookWHERElast_name=’Smith’  当有大量的行正在被插入表中时,要避免在本表一个自然增长(例如,identity列)的列上建立聚簇索引。如果你建立了聚簇的索引,那么insert的性能就会大大降低。因为每一个插入的行必须到表的最后,表的最后一个数据页。
  非聚簇索引指定表中的逻辑顺序,一个表上可以建立多达249个非聚簇索引,它查询的速度比不建立索引快,但比聚簇索引慢,插入数据比聚簇索引快,因为纪录直接被追加到数据末尾。可以在以下情况下考虑使用非聚簇索引。
(1)在有很多不同值的列上可以考虑使用非聚簇索引,如employee表中的emp_id列可以建立非聚簇索引。
(2)查询结果集返回的是少量或单行的结果集。例如  
select*fromemployeewhereemp_id=’pcm9809f’  
(3)查询语句中orderby子句的列上可以考虑使用非聚簇索引。

    3.2常用的计算字段(如总计、最大值等)可以考虑存储到数据库实体中。  例如仓库管理系统中有材料入库表,其字段为:材料编号、材料名称、型号,单价,数量…,而金额是用户经常需要在查询和报表中用到的,在表的记录量很大时,有必要把金额作为一个独立的字段加入到表中。这里可以采用触发器以在客户端保持数据的一致性。

    3.3用where子句来限制必须处理的行数。  在执行一个查询时,用一个where子句来限制必须处理的行数,除非完全需要,否则应该避免在一个表中无限制地读并处理所有的行。例如:  |||   select qty from sales where stor_id=’7131’是很有效的,比无限制的查询selectqtyfromsales有效,避免给客户的最后数据选择返回大量的结果集。当然也可以用TOP限制返回结果集的行数。

    3.4尽量使用数字型字段。  一部分开发人员和数据库管理人员喜欢把包含数值信息的字段设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

    3.5查询语句的优化。  对于一条复杂的查询语句来说,对相同查询条件的实现一般总可以有多种不同的表达方法,而不同的表达会使数据库的响应速度大相径庭。据统计,约有80%以上的性能问题是由于使用了不恰当的查询语句造成的,因此SQL语句的质量对整个系统效率有重大关系。
下面介绍查询语句优化方面的一些技巧:
(1)避免使用不兼容的数据类型。例如float和int、char和varchar、 binary和varbinary是不兼容的。数据类型的不兼容可能使优化器无法执行一些本来可以进行的优化操作。例如:   SELECTnameFROMemployeeWHEREsalary>60000  在这条语句中,如salary字段是money型的,则优化器很难对其进行优化,因为60000是个整型数。这条语句可以改为:  SELECTnameFROMemployeeWHEREsalary>$60000
  (2)尽量避免在Where条件里使用非聚合表达式,因为非聚合表达式很难利用到索引,通常SQLServer不得不进行大规模的扫描。像!=或<>、 ISNULL或ISNOTNULL、IN,NOTIN等这样的操作符构成的表达式都是非聚合表达式。非聚合表达式会导致查询效率大大降低。例如:   SELECTidFROMemployeeWHEREid!='B%'  优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行。
   (3)尽量避免在WHERE子句中对字段进行函数或表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:  
SELECT*FROMemployeeWHEREsalary/2=100应改为: 
SELECT*FROMemployeeWHEREsalary=100*2   SELECT*FROMemployeeWHERESUBSTRING(emp_id,1,3)=’PCM’应改为:
SELECT*FROMemployeeWHEREemp_idLIKE‘5378%’   SELECTmember_number,first_name,last_nameFROMmembers   WHEREDATEDIFF(yy,datofbirth,GETDATE())>21应改为:
SELECT member_number,first_name,last_name FROM members WHERE dateofbirth  即:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
(4)避免使用LEFTJOIN   SQL的一个有价值的常用功能是LEFTJOIN。它可以用于检索第一个表中的所有行、第二个表中所有匹配的行、以及第二个表中与第一个表中不匹配的所有行。例如,如果希望返回每个客户及其定单,使用LEFTJOIN则可以显示有定单和没有定单的客户。LEFTJOIN消耗的资源非常之多,因为它们包含与 NULL(不存在)数据匹配的数据。因此在构造查询语句时尽量避免使用LEFTJOIN。
(5)尽量避免在索引过的字符数据中,使用非打头字母搜索。这也使得引擎无法利用索引。  见如下例子:  
SELECT*FROMmembersWHEREfirst_nameLIKE‘%MA%’   SELECT*FROMmembersWHERESUBSTING(first_name,3,1)=’MA’   SELECT*FROMmembersWHEREfirst_nameLIKE‘MA%’  即使NAME字段建有索引,前两个查询依然无法利用索引完成加快操作,引擎不得不对全表所有数据逐条操作来完成任务。而第三个查询能够使用索引来加快操作。(6)避免相关子查询  一个列的标签同时在主查询和 WHERE子句中的查询中出现,那么很可能当主查询中的列值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此应当尽量避免子查询。可 以采用子查询“展平”技术,将子查询转变为连接,半连接或反连接,从而达到优化查询的目的。例如查询找出有工资超过10000的职工所在的部门名称。   SELECT部门名FROM部门WHERE部门号IN  (SELECT部门号FROM职工WHERE工资>10000)  此查询将扫描部门表的 每一行查找所有满足子查询条件的职工记录。可以将部门表作为连接的内表,在这种情况下,查询作为通常的连接来执行,首先对职工表进行唯一的部门号筛选,以 消除冗余的部门号,转化后的语句为:  SELECTB.部门名FROM(SELECTDISTINCT部门号FROM职工WHERE工 资>10000,部门DWHEREB.部门号=D.部门号  对于SQL语句的优化方法还有很多,在这里就不一一例举了。
参考技术D 索引,重新写SQL。

sqlserver的like '%xxx%'优化,全文索引

2000万行的数据表,首先对Address字段做\'%xxx%\'模糊查询

这是估计的查询计划

这是估计的实际查询结果,用了37秒才查询完成

 

 

 

 

还是之前的数据,但是这一次使用\'xxx%\'来做查询,现在还没有做索引

 

查询速度为10秒,依然是做了全表扫描

 

 

 

 

接下来的这个不是模糊查询,直接的=,查询多了一个步骤“并行度”

 

三秒钟完成查询,也是很慢的,应该都是走了全表扫描

 

 

 

 

现在为Address字段建立一个普通索引

 

 

建好普通索引之后尝试进行\'%xxx%\'查找,从查询计划来看,\'%xxx%\'是无法利用到普通索引的

 

 

果然,查询耗时和没有建立索引之前一样,基本没变

 

 

 

现在尝试查询\'xxx%\',根据查询计划可以看到,这种查询可以走刚刚我们建立的普通索引

 

查询结果为4秒,之前没有建立索引的时候查询结果为10秒,缩小了一倍

 

 

接着,直接=查找,可以看出利用了索引

 

查询耗时0秒,降到了毫秒级别,从这点可以看出,普通的非聚集索引对于直接匹配(=)查询的支持是最好的,然后是like \'xxxx%\',而like \'%xxx%\'不支持

 

 

然后我们在Address字段上建立一个全文索引

 

 

 

下面是全文索引的使用语法,以及查询过程

 

全文索引添加之后,查询时间为2秒,还是有点慢,后来测试了几次,一般是在一秒左右

 

 

 

 

 

另外SQLServer2008的全文索引貌似不会立马建立完成,而是需要在后台等待一段时间才能完全建立,在这段时间里面查询返回的结果是不一样的。

如下图,两次查询后一次的结果比前一次多,全文索引正在建立中,最后会有一个稳定的状态。

 

以上是关于如何做SqlServer 数据查询优化!的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver的like '%xxx%'优化,全文索引

SQL server2005上千万条数据分页查询怎么做优化?

如何优化Sql server 大数据量时使用 like 查询的速度?或有啥别的方法实现模糊查询?

如何进行SQL性能优化

提高sql server查询优化器结果的方法

SqlServer优化:当数据量查询不是特别多,但数据库服务器的CPU资源一直100%时,如何优化?