解决方法
这是好的,但有时可能是坏的.
参数嗅探是关于查询优化器使用提供的参数的值来确定最佳查询计划可能的.许多选择之一和一个非常容易理解的是,如果整个表应该被扫描以获取值,或者使用索引寻找将更快.如果您的参数中的值具有高度的选择性,则优化程序可能会使用seek构建查询计划,如果不是查询将对表进行扫描.
然后,查询计划被缓存并重新用于具有不同值的连续查询.参数嗅探的不良部分是当缓存的计划不是其中一个值的最佳选择.
样品数据:
create table T ( ID int identity primary key,Value int not null,AnotherValue int null ); create index IX_T_Value on T(Value); insert into T(Value) values(1); insert into T(Value) select 2 from sys.all_objects;
T是一个具有数千行的值,在Value上具有非聚集索引.有一行,其中值为1,其余的值为2.
示例查询:
select * from T where Value = @Value;
查询优化器在这里的选择是要进行聚簇索引扫描,并检查where子句对于每一行,或使用Index Seek来查找与之匹配的行,然后执行Key Lookup,以获取所要求的列中的值列列表.
当嗅探值为1时,查询计划将如下所示:
当嗅探的值为2时,它将如下所示:
在这种情况下,参数嗅探的不良部分发生在查询计划构建时,嗅探1,但稍后执行,值为2.
你可以看到密钥查询执行了2352次.扫描显然是更好的选择.
总而言之,我会说,参数嗅探是一件好事,您应该尝试通过使用参数来查询来尽可能地发生.有时可能会出错,在这种情况下,很有可能是由于数据不正确而导致您的统计数据混乱.
更新:
这是一个针对几个dmv的查询,您可以使用它来查找系统中最昂贵的查询.更改为order by子句对您正在寻找的内容使用不同的标准.我认为TotalDuration是开始的好地方.
set transaction isolation level read uncommitted; select top(10) PlanCreated = qs.creation_time,ObjectName = object_name(st.objectid),QueryPlan = cast(qp.query_plan as xml),QueryText = substring(st.text,1 + (qs.statement_start_offset / 2),1 + ((isnull(nullif(qs.statement_end_offset,-1),datalength(st.text)) - qs.statement_start_offset) / 2)),ExecutionCount = qs.execution_count,TotalRW = qs.total_logical_reads + qs.total_logical_writes,AvgRW = (qs.total_logical_reads + qs.total_logical_writes) / qs.execution_count,TotalDurationMS = qs.total_elapsed_time / 1000,AvgDurationMS = qs.total_elapsed_time / qs.execution_count / 1000,TotalcpuMS = qs.total_worker_time / 1000,AvgcpuMS = qs.total_worker_time / qs.execution_count / 1000,TotalCLRMS = qs.total_clr_time / 1000,AvgCLRMS = qs.total_clr_time / qs.execution_count / 1000,TotalRows = qs.total_rows,AvgRows = qs.total_rows / qs.execution_count from sys.dm_exec_query_stats as qs cross apply sys.dm_exec_sql_text(qs.sql_handle) as st cross apply sys.dm_exec_text_query_plan(qs.plan_handle,qs.statement_start_offset,qs.statement_end_offset) as qp --order by ExecutionCount desc --order by TotalRW desc order by TotalDurationMS desc --order by AvgDurationMS desc ;