查询优化器基于当前的统计信息和参数,衡量开销以后,选择“最优”的执行计划,须要注意的是,“最优”是相对的,优化器不可能穷举全部的执行计划来评估其开销,这个“最优”的标准是对当前参数和当前的统计信息来讲的,优化器从生成的备选执行计划中选择开销最小的。因为执行计划的编译和生成是很耗费资源和时间的,所以,SQL Server会把生成的任一执行计划缓存起来,以便重用。算法
因为关系表的数据和结构可能发生改变,数据更新会致使统计信息过期,而以前的参数可能不具备表明性,使得已生成的执行计划不能表明其余参数值,致使查询性能低下。所以,应当监控执行计划的性能,当发现参数嗅探问题时,应该及时修改代码以重编译;当发现统计信息过时时,应及时更新统计信息等。sql
SQL Server使用特定的缓存机制,以重用第一次执行查询时生成的执行计划,总的来讲,SQL Server内部有如下四种执行计划缓存机制:数据库
对于Adhoc查询的缓存,是SQL Server自动进行的,用户不能干预,然后两种是用户能够干预的,用户能够经过优化代码来复用“模板化”的查询。所谓模板化语句,是指除了个别的常量发生变化以外,语句主体不变,能够把变化的常量做为一个参数,不变的语句主体做为一个模板来处理,SQL Server优化器把这个模板编译成执行计划,传入不一样的参数会使用相同的执行计划。缓存
1,Ad Hoc查询缓存性能优化
对于任意一个Ad Hoc查询,SQL Server都会缓存它的执行计划,可是,只有当批处理语句的文本彻底匹配时,才会复用已缓存的执行计划,彻底匹配的处理过程是:并发
大量的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时,执行计划会被移除内存。
除了这两个条件以外,当遇到下面的条件时,执行计划一会被移除内存,被从新编译:
在执行计划执行过程当中,执行计划被从新编译,是优化器根据表结构,索引结构和统计信息作出优化的结构,目的是为了不继续使用不合适的执行计划。
修改存储过程,触发器等模块(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:
1,查询提示
使用option来设置查询提示,
2,关联提示
在 join关键字前面使用Loop,Merge和Hash来控制关联的算法
3,表提示
在引用的表名后面,经过with()来设置表提示 table_name with(hints),
当使用索引时,使用 with(index(index_name))来设置,
参考文档: