我对某些特定的sql语句性能有一个奇怪的问题。我有一个sql语句(内容,我认为并不重要)。当运行.NET应用程序(使用EF作为数据库访问; SQL获取参数化)并使用SQL事件探查器捕获数据时,我得到以下结果:
但是,当通过SSMS运行相同 SQL语句时(首先执行set statistics io on
和set statistics time on
),我得到以下结果:
Table 'mytable'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 16 ms, elapsed time = 138 ms.
两个SQL都在相同的用户上下文下执行,但显然不同的连接。如您所见,通过SSMS运行相同查询比通过应用程序运行它更快。
我应该在哪里寻找差异,例如什么触发不同的读取和持续时间可能是,问题是参数嗅探(虽然我不知道如何)?
答案 0 :(得分:1)
问题是因为两个执行中生成的执行计划application / SSMS是不同的。
正如您所假设的,问题是参数嗅探。
为什么即使你正在运行的查询是相同的?
好吧,因为除了在计划缓存中查找执行查询的执行计划之外,SQL Server还会查看会话设置(ANSI_NULLS,ARITHABORT等)。这两种情况下的默认会话设置不同。
我相信.NET EF参数 ARITHABORT 设置为OFF,而在SSMS中它是ON(have a look at this article - Slow in the application, fast in SSMS)。
因此,最终您将在计划中为同一查询缓存2个不同的执行计划,但是针对不同的会话参数。
我会开始寻找重写这个查询。我最近遇到了同样的问题,我尝试在两个会话(应用程序/ SSMS)中匹配会话参数,有一段时间生成的执行计划很好。
但是一段时间之后,当计划被推出计划缓存时,生成了一个新的次优计划并继续使用(参数再次嗅探),所以这是一个非常恶毒的循环,我不建议将其作为长期解决方案。
作为一个长期解决方案,我建议您重新编写查询/查询,如果还没有适当的索引,可以添加一些正确的索引。
答案 1 :(得分:0)
此查询将帮助您获得多个执行计划。 SELECT * FROM sys.dm_exec_procedure_stats WHERE object_id =?
检查SSMS SET选项: 工具>选项>查询执行> SQL Server>先进
您可以通过以下查询查看两个执行之间的区别: SELECT * FROM sys.dm_exec_plan_attributes(plan_handle)
选项----->值强>
ANSI_PADDING -----→1
平行计划-----> 2
FORCEPLAN -----> 4
CONCAT_NULL_YIELDS_NULL -----> 8
ANSI_WARNINGS -----> 16
ANSI_NULLS -----> 32
QUOTED_IDENTIFIER -----> 64
ANSI_NULL_DFLT_ON -----> 128
如何计算此值和选项?
从结果表中我们得到第一个值。这是4345。
接下来我们需要找到4345旁边的最高值。在这种情况下,它是4096.
一旦我们有了这两个值,我们就需要找到它们的区别。这是4345和4096的差异,这将导致249。
我们需要按照上述步骤直到结束。值的差异是用于该特定过程的执行计划的选项。