SqlServer奇怪的SQL语句性能

SqlServer奇怪的SQL语句性能,sql,sql-server,tsql,Sql,Sql Server,Tsql,我对某些特定的sql语句性能有一个奇怪的问题。我有一个sql语句(我认为内容并不重要)。在运行.NET应用程序(使用EF作为DB访问;SQL参数化)并使用SQL Profiler捕获数据时,我会得到以下结果: 中央处理器:28.253 全文:8.503.799 写入:0 持续时间:54.274(略多于54秒) 但是,当通过SSMS运行相同的SQL语句时(首先执行在上设置统计io和在上设置统计时间),我会得到以下结果: 表格“mytable”。扫描计数1,逻辑读取4,物理读取0,预读0,lob

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

  • 中央处理器:28.253
  • 全文:8.503.799
  • 写入:0
  • 持续时间:54.274(略多于54秒)
但是,当通过SSMS运行相同的SQL语句时(首先执行
上设置统计io和
上设置统计时间),我会得到以下结果:

表格“mytable”。扫描计数1,逻辑读取4,物理读取0,预读0,lob逻辑读取0,lob物理读取0,lob预读0。

表格“工作台”。扫描计数0,逻辑读取0,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。

SQL Server执行时间:
CPU时间=16毫秒,运行时间=138毫秒。

这两个SQL都是在相同的用户上下文下执行的,但连接明显不同。如您所见,通过SSMS运行相同的查询要比通过应用程序运行快得多


我应该在哪里查找差异,例如,什么触发了不同的读取和持续时间?问题是否可能是参数嗅探(尽管我不知道怎么做)?

问题是因为在两个执行(应用程序/SSM)中生成的执行计划不同

正如您所假设的,问题在于参数嗅探

为什么会这样,即使您运行的查询是相同的?

好的,因为除了在执行查询的计划缓存中查找执行计划外,SQL Server还查看会话设置(ANSI_NULLS、ARITHABORT等)。这两种场景中的默认会话设置不同

我相信.NET EF参数已ARITHABORT设置为OFF,而在SSMS中它是ON()

因此,最终您的计划缓存中会有两个不同的执行计划,用于相同的查询,但用于不同的会话参数

我将开始寻找重新编写此查询的方法。我最近遇到了同样的问题,我尝试在两个会话(应用程序/SSM)中匹配会话参数,并且有一段时间生成的执行计划很好

但一段时间之后,当计划被推出计划缓存时,一个新的次优计划被生成并继续使用(再次进行参数嗅探),因此这是一个相当恶性循环,我不建议将其作为长期解决方案


作为一个长期的解决方案,我建议重新编写您的查询,如果您还没有索引,可能会添加一些适当的索引。

此查询将帮助您获得多个执行计划。 从sys.dm_exec_procedure_stats中选择*其中object_id=

检查SSMS集合选项: 工具>选项>查询执行>SQL Server>高级

通过以下查询,您可以看到两次执行之间的差异: 从sys.dm_exec_plan_属性(plan_句柄)中选择*

选项------>值

  • ANSI_填充------>1

  • 平行计划------>2

  • 强制计划------>4

  • CONCAT_NULL_产量_NULL------>8

  • ANSI_警告------>16

  • ANSI_空值------>32

  • 引用的标识符------>64

  • ANSI\U NULL\U DFLT\U ON------>128

  • ANSI_NULL_DFLT_关闭------>256
  • NoBrowseTable表示计划不使用工作表来实现FOR BROWSE操作。-->512
  • TriggerRow表示计划包含触发器后增量表的单行优化。-->1024
  • ResyncQuery表示查询是由内部存储系统提交的 程序。-->2048
  • ARITH_中止------>4096
  • 数字循环中止------>8192
  • 日期优先------>16384
  • 日期格式------>32768
  • 语言ID------>65536
  • On表示 在编译计划时,数据库选项参数化设置为强制。-->131072
  • 行数-适用于:SQL Server 2012到SQL Server 2016------->262144
如何计算这些值和选项?

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

  • 下一步,我们需要从表中找到4345旁边的最大值。在这种情况下是4096

  • 一旦我们有了这两个值,我们就需要找出它们的差异。这是4345和4096的差值,结果是249

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


您可以先通读这篇文章,谢谢您的回答。在末尾添加“选项(重新编译)”怎么样?这基本上可以解决参数嗅探错误,但每次都会强制重新编译。我已经检查过了,所有索引都放好了,总的来说,查询并没有那么复杂,只是表有几百万行。@你可以用
选项(重新编译)
来解决它,但你真的想这样做吗?每秒重新编译的次数越多,CPU使用率越高。我在这里用金伯利·特里普(Kimberly Tripp)的口号:-当谈论稳定性时,我谈论的是数据倾斜。您的数据是否非常倾斜,以至于您需要为每个参数制定新的计划?如果是,则选择“重新编译”,否则宁愿缓存它。@我要做的是尝试将查询拆分为两个或多个查询。第一个查询是我从大表中引入所有数据,并将所有这些行放在一个临时表中
从bigTblA中选择a、b、c进入#tmp..
然后在我的第二个查询中,我将加入这个#tmp表wi