慢速运行查询,CF 9& MSSQL 2008;腐败的执行计划?

时间:2014-10-10 01:30:24

标签: sql-server-2008 coldfusion coldfusion-9

我多年来一直致力于Coldfusion / MS SQL,这是我见过的最奇怪的问题之一。问题本身已经解决,但我并不真正了解发生的事情;这个问题试图清楚地了解可能的原因。

问题

在稳定的生产环境中,没有明显的原因,一个查询开始返回大约1,000-1,500毫秒(比通常慢大约10倍)。我能够把它分离出来:

<cfquery datasource="#ds#" name="query">
   select 1
   from eLearning.v_courseCompletion cc
   where 
      cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and
      cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and 
      cc.currentCourseCompleted = 1
</cfquery>

奇怪的是,这种行为在循环中会加剧,即使只有一次迭代,就像在这个例子中一样:

<cfloop from="1" to="1" index="i">
   <cfquery datasource="#ds#" name="query">
      select 1
      from eLearning.v_courseCompletion cc
      where 
         cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and
         cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and 
         cc.currentCourseCompleted = 1
   </cfquery>
</cfloop>

这应该和上面完全一样,对吗?循环应该没有效果,但相反,此测试运行速度慢约10倍,返回7,000-16,000毫秒。这就是问题的检测方法;如果循环迭代超过5或6次请求将超时,则查询(隐藏在对象方法中)是从循环体调用的。

对我而言,这表明Coldfusion方面存在问题,但重新启动服务,或者确实是机器,什么也没做。

同时,一旦被隔离,我注意到对查询本身进行任何更改都会导致性能恢复到预期的水平,大约150-190毫秒。例如:

  • 更改所选字段(例如select *
  • 删除表别名(cc
  • 使用内联值替换<cfqueryparam>
  • 删除任何条件

任何这些变化&#34;已修复&#34;问题但是,当运行原始查询时,性能问题将会返回。

解决方案

此时我猜测查询的执行计划已损坏或者某些内容,some Googling,并且针对数据库服务器运行DBCC FREEPROCCACHE。此立即修复了问题。很好,问题解决了....

问题

从那时起,我已经做了一些研究,而且共识似乎是执行计划并没有被破坏&#34;。 some talk similar problems parameter sniffing与存储过程和{{3}}一起发生,但我在这里没有使用任何sp。我们正在从一个相当复杂的视图(eLearning.v_courseCompletion)中选择嵌套连接。这是问题吗?

基本上,这里发生了什么?如何阻止它再次发生?

..和CF中的循环连接到底是什么?!?

版本

  • Coldfusion 9.0.2.282541(64位)
  • SQL Server Express 10.50.4297(64位)
  • 两台服务器均为Win Server 2008 R2 Datacenter(64位)

1 个答案:

答案 0 :(得分:6)

使用cfqueryparam时,您正在使用存储过程。如果不使用cfqueryparam,则只需将查询作为“自由文本”批处理查询发送。当您使用cfqueryparam时,您将使用sp_executeSQL()发送您的查询,sp_executeSQL()本身将您的查询体作为参数发送。这允许查询计划缓存。如果它看到相同的查询,它将使用它为该特定计划保存的统计信息。这意味着,如果它运行了一些非常奇怪的数据并且执行查询的想法不好,那么下一次迭代将使用相同的计划,这对于该查询的99%的用例来说是一个“糟糕的计划”,但对于那个奇怪的实例来说,这可能是一个很好的计划。

使用sp_execute SQL执行的每个查询也返回一个数字句柄,JDBC驱动程序可以使用该句柄简单地告诉SQL它可以使用哪个计划,基本上是一个快捷方式。这在CFadmin的DSN设置中称为“max pooled statements”。将其设置为0或1000不会影响您将利用sp_executeSQL的计划缓存这一事实。

http://blogs.msdn.com/b/turgays/archive/2013/09/18/exec-vs-sp-executesql.aspx

StackOverflow很好地证明了这一点,如果一个特定的高级用户在构建查询统计数据之前加载他们的帐户页面上有数百万个徽章和积分,那么每个其他只有少数用户的用户的数据会搞乱百分之一点和一些徽章,使他或她的页面变慢。