性能调优5:执行计划

查询优化器基于当前的统计信息和参数,衡量开销以后,选择“最优”的执行计划,须要注意的是,“最优”是相对的,优化器不可能穷举全部的执行计划来评估其开销,这个“最优”的标准是对当前参数和当前的统计信息来讲的,优化器从生成的备选执行计划中选择开销最小的。因为执行计划的编译和生成是很耗费资源和时间的,所以,SQL Server会把生成的任一执行计划缓存起来,以便重用。算法

因为关系表的数据和结构可能发生改变,数据更新会致使统计信息过期,而以前的参数可能不具备表明性,使得已生成的执行计划不能表明其余参数值,致使查询性能低下。所以,应当监控执行计划的性能,当发现参数嗅探问题时,应该及时修改代码以重编译;当发现统计信息过时时,应及时更新统计信息等。sql

一,缓存机制

SQL Server使用特定的缓存机制,以重用第一次执行查询时生成的执行计划,总的来讲,SQL Server内部有如下四种执行计划缓存机制:数据库

  • Ad hoc 查询缓存
  • 参数化Ad Hoc查询缓存
  • sys.sp_executesql 执行的查询,是一种参数化的查询语句
  • 存储过程

对于Adhoc查询的缓存,是SQL Server自动进行的,用户不能干预,然后两种是用户能够干预的,用户能够经过优化代码来复用“模板化”的查询。所谓模板化语句,是指除了个别的常量发生变化以外,语句主体不变,能够把变化的常量做为一个参数,不变的语句主体做为一个模板来处理,SQL Server优化器把这个模板编译成执行计划,传入不一样的参数会使用相同的执行计划。缓存

1,Ad Hoc查询缓存性能优化

对于任意一个Ad Hoc查询,SQL Server都会缓存它的执行计划,可是,只有当批处理语句的文本彻底匹配时,才会复用已缓存的执行计划,彻底匹配的处理过程是:并发

  • SQL Server根据批处理语句的文本计算出一个Hash值,对后续的Ad Hoc查询的文本一样计算Hash值,当两个Hash值相同时,说明两个批处理的文本彻底相同,至关于同一个查询的重复执行,SQL Server优化器会复用已缓存的执行计划。
  • 若是Ad Hoc查询的文本有任意一个字符发生变化(好比,大写字符变小写字符,不一样的换行,多了一个空格等),都会致使计算出的Hash值不一样,进而不能复用执行计划。也就是说,Ad Hoc查询的文本必须彻底匹配才能复用执行计划。

大量的Ad Hoc查询缓存会占用计划缓存的空间,这些缓存可能只会被使用一次,之后不再会被使用。若是数据库系统中存在大量的一次性查询语句,应设置Server 级别的性能优化选项:Optimize for Ad hoc Wrokloads。oop

“针对即席工做负载进行优化”是一个Server级别的性能优化选项,用于提升包含许多临时批处理的工做负载的计划缓存的效率,若是把该选项设置为True,则数据库引擎在首次编译批处理时只保留计划缓存中的一个存根,而不是存储整个执行计划。当再次调用该批处理时,数据库引擎识别出该批处理在以前被执行过,进而从计划缓存中删除该执行计划的存根,并把彻底编译的执行计划添加到计划缓存中。当非参数化的Ad-Hoc查询较多时,能够避免计划缓存存储过多的不会被复用的执行计划。性能

2,参数化Ad-Hoc优化

SQL Server 自主决定是否把查询中的常量做为参数来对待,除了常量不一样以外,其余语句主体都相同,这就是这个查询语句的模板,不一样的参数使用相同的执行计划。spa

例如,对于如下两个查询语句,除了常量1和2不一样以外,其余语句都相同,

select ID, Name from dbo.Users where ID=1
select ID, Name from dbo.Users where ID=2

SQL Server对该语句作参数化处理,获得模板,只要语句符合该模板,优化器就复用已缓存的执行计划。

select ID, Name from dbo.Users where ID=@id

3,Prepared 查询缓存

用户使用sys.sp_executesql 控制参数和模板,只要模板相同,而参数不一样,均可以复用已缓存的执行计划。

4,存储过程

用户建立的存储过程,在第一次执行时,编译和生成执行计划,并缓存到计划缓存中,当下次调用相同的存储过程,即便使传递的参数不一样,SQL Server都会复用执行计划。

二,参数嗅探

参数嗅探是指在建立存储过程,或者参数化查询的执行计划时,根据传入的参数进行预估并生成执行计划。SQL Server生成的执行计划对当前参数来讲是最优的,而对其余大多数参数来讲,是很是低效的。有些时候,针对一个查询的第一次传参,已经产生了一个执行计划,当后续传参时,因为存在对应参数的数据分布等问题,致使原有的执行计划没法高效地响应查询请求,这就出现参数嗅探问题。

参数嗅探的本质是优化器根据参数来生成的执行计划不是最优的,致使优化器在复用执行计划时,语句的查询性能变得十分低下。对于参数嗅探问题,必须从新生成执行计划,可使用语句重编译,编译提示(optimize for)等功能来避免。

三,影响执行计划复用的因素

SQL Server不会永久保存计划的缓存,而且存在缓存中的执行计划也不会永久不变,每一个计划都会有一个Age值,当SQL Server探测到内存压力时,会触发Lazy Writer进程,用于清空全部的脏页,释放数据缓存。当扫面到计划缓存时,会下降Age值,当复用一次计划时,会增长Age值。当系统遇到内存压力,或Age值降到0时,执行计划会被移除内存。

除了这两个条件以外,当遇到下面的条件时,执行计划一会被移除内存,被从新编译:

  • 查询引用的基础表的结构被更改
  • 查询引用的索引被更改或被删除
  • 查询引用的统计信息被更新
  • 执行计划被强制从新编译(详见本问第四小节)
  • 单一查询中混合了DDL和DML操做,也称为延迟编译
  • 在查询中修改set选项
  • 查询所用到的临时表的结构被修改
  • 等等

在执行计划执行过程当中,执行计划被从新编译,是优化器根据表结构,索引结构和统计信息作出优化的结构,目的是为了不继续使用不合适的执行计划。

四,强制从新编译执行计划

修改存储过程,触发器等模块(Module)可以使其执行计划从新编译,除此以外,还有其余方法,可以强制从新编译执行计划

1,标记,下次从新编译

使用该存储过程,标记一个执行模块(SP,Trigger,User-Defined Function)在下次执行时,从新编译执行计划

sys.sp_recompile [ @objname = ] 'object'

2,不复用执行计划

在建立存储过程时,使用WITH RECOMPILE 选项,在每次执行SP时,都从新编译,使用新的执行计划。

CREATE PROCEDURE dbo.usp_procname 
    @Parameter_Name varchar(30) = 'Parameter_default_value'
WITH RECOMPILE

3,执行时从新编译

在执行存储过程时,从新编译存储过程的执行计划

exec dbo.usp_procname @Parameter_name='Parameter_value' 
WITH RECOMPILE

4,语句级别的从新编译

在SP中,使用查询选项 option(recompile),只从新编译该语句级别的执行计划

select column_name_list
from dbo.tablename
option(recompile)

SQL Server在执行查询以后,查询提示(RECOMPILE)指示存储引擎将计划缓存抛弃,在下次执行存储过程时,强制查询优化器从新编译,生成新的执行计划。在从新编译时,SQL Server 优化器使用当前的变量值生成新的计划缓存。

五,控制执行计划

优化器会根据查询选择执行计划,选择索引,表关联算法等,可是,当发现优化器选择了低效的执行计划时,可使用hint来控制执行计划,SQL Server提供了三种类型的hint:

  • 查询提示(query hint):告知优化器在整个查询过程当中都应用某个提示,
  • 关联提示(join hint):告知优化器在关联时使用特定的关联算法
  • 表提示(table hint):告知优化器使用表扫描,仍是表上特定的索引

1,查询提示

使用option来设置查询提示,

  • 用于group by 聚合,能够控制分组的算法:hash group 和order group
  • 用于控制关联的算法, option(hash join)
  • 一般状况下,优化器决定表关联的顺序,可使用force order选项,使优化器按照join的顺序来关联, option(force order)
  • 使用maxdop来肯定语句执行的最大并发度,option(maxdop 1),取消并发执行。
  • 按照指定的参数来优化 option(optimize for (@para_name= constant_value))

2,关联提示

在 join关键字前面使用Loop,Merge和Hash来控制关联的算法

3,表提示

在引用的表名后面,经过with()来设置表提示 table_name with(hints),

当使用索引时,使用 with(index(index_name))来设置,

 

参考文档:

相关文章
相关标签/搜索