use*_*183 13 sql-server parameter-sniffing
我已经阅读了很多关于参数嗅探的文章,但目前尚不清楚这是好还是坏.任何人都可以通过一个简单的例子来解释
有没有办法自动检测错误的计划分配给特定的声明?
提前致谢.
Mik*_*son 20
它很好但有时可能很糟糕.
参数嗅探是关于查询优化器使用提供的参数的值来确定可能的最佳查询计划.许多选择中的一个和非常容易理解的选择之一是,应该扫描整个表以获取值,还是使用索引搜索更快.如果参数中的值具有高度选择性,优化器可能会使用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;
Run Code Online (Sandbox Code Playgroud)
T
是一个包含几千行的表,其值为非聚集索引.有一行是值1
,其余的是值2
.
示例查询:
select *
from T
where Value = @Value;
Run Code Online (Sandbox Code Playgroud)
查询优化器在此处的选择是执行聚簇索引扫描并针对每一行检查where子句,或使用索引查找来查找匹配的行,然后执行密钥查找以从要求的列中获取值列列表.
当嗅探值是1
查询计划时,它将如下所示:
当嗅觉值是2
这样时,它将如下所示:
在这种情况下参数嗅探的不良部分发生在构建查询计划时嗅探a 1
但稍后执行的值为2
.
您可以看到Key Lookup执行了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
;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5688 次 |
最近记录: |