SqlServer奇怪的SQL语句性能

时间:2017-03-21 09:22:18

标签: sql sql-server tsql

我对某些特定的sql语句性能有一个奇怪的问题。我有一个sql语句(内容,我认为并不重要)。当运行.NET应用程序(使用EF作为数据库访问; SQL获取参数化)并使用SQL事件探查器捕获数据时,我得到以下结果:

  • CPU:28.253
  • 阅读:8.503.799
  • 写道:0
  • 持续时间:54.274(略高于54秒)

但是,当通过SSMS运行相同 SQL语句时(首先执行set statistics io onset 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运行相同查询比通过应用程序运行它更快。

我应该在哪里寻找差异,例如什么触发不同的读取和持续时间可能是,问题是参数嗅探(虽然我不知道如何)?

2 个答案:

答案 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

  • ANSI_NULL_DFLT_OFF -----> 256
  • NoBrowseTable表示该计划不使用工作表来实现FOR BROWSE操作.-----> 512
  • TriggerOneRow表示该计划包含AFTER触发器增量表的单行优化.-----> 1024
  • ResyncQuery表示查询是由内部系统提交的 程序.-----> 2048
  • ARITH_ABORT -----> 4096
  • NUMERIC_ROUNDABORT -----> 8192
  • DATEFIRST -----> 16384
  • DATEFORMAT -----> 32768
  • LanguageID -----> 65536
  • UPON表示 数据库选项PARAMETERIZATION在编译计划时设置为FORCED .-----> 131072
  • ROWCOUNT - 适用于:SQL Server 2012到SQL Server 2016 -----> 262144

如何计算此值和选项?

  • 从结果表中我们得到第一个值。这是4345。

  • 接下来我们需要找到4345旁边的最高值。在这种情况下,它是4096.

  • 一旦我们有了这两个值,我们就需要找到它们的区别。这是4345和4096的差异,这将导致249。

  • 我们需要按照上述步骤直到结束。值的差异是用于该特定过程的执行计划的选项。