防止ADO.NET使用sp_executesql

时间:2010-01-11 11:30:00

标签: sql-server ado.net

在我们的SQL Server 2005数据库中(使用带有DBCC FREEPROCCACHE和的Management Studio进行测试 DBCC DROPCLEANBUFFERS),以下语句很快(~0.2s编译时间,~0.1s执行时间):

SELECT ... FROM ... WHERE a = 1 AND b = '' ...

然而,以下陈述很慢(编译时间约为0.2秒, 7-11s 执行时间):

exec sp_executesql N'SELECT ... FROM ... WHERE a = @a AND b = @b ...', N'@a int, @b nvarchar(4000), ...', @a=1, @b=N'', ...

SQL Server选择不同的执行计划,尽管查询相同。这是有道理的,因为在第一种情况下,SQL Server具有ab的实际值以及所有其他可用参数,并且可以使用统计信息来创建更好的计划。显然,参数的具体值的查询计划比通用的好得多,绝对超过任何“查询计划缓存”性能优势。

现在我的问题:在执行参数化查询时,ADO.NET似乎总是使用第二个选项(sp_executesql),通常有意义(查询计划缓存等)。然而,在我们的案例中,这会导致性能下降。那么,有没有办法

  • 强制ADO.NET使用与sp_executesql不同的内容(即SQL Server查询分析器将实际参数值考虑在内的内容)或
  • 强制SQL Server重新计算传递给sp_executesql 的SQL的查询计划,并将参数值考虑在内

请不要告诉我,我必须回到丑陋,陈旧,危险的sql = "WHERE b = " + quoteAndEscape(parameterB) ......

将SQL放入存储过程没有任何区别(慢,有和没有WITH RECOMPILE)。我没有发布实际的SQL语句,因为它非常复杂(连接多个表,包括子SELECT和聚合)。

4 个答案:

答案 0 :(得分:4)

旧线程我知道,但我只是通过谷歌搜索几乎完全相同的短语!我有完全相同的问题(查询在Management Studio中使用参数运行得非常快,但后来通过ADO.Net非常慢)并通过“exec sp_execute”在Management Studio中运行查询来复制问题。这两个执行计划非常不同,即使使用Optimize for query提示,所以我所做的是将一些数据初始选择到临时表中。这似乎有所不同,并且鉴于你说你的查询是一个复杂的问题,它可能会很好地改变你的情况 - 我不太确定它是如何工作的,但它似乎将执行计划付诸实施即使使用sp_execute也行。

答案 1 :(得分:2)

您可以尝试OPTIMIZE FOR query hint(引用):

  

指示查询优化器使用a   局部变量的特定值   编译查询时   优化。该值仅用于   在查询优化期间,而不是   在查询执行期间。优化   可以抵消参数检测   优化器的行为还是可以的   在创建计划指南时使用

答案 2 :(得分:2)

我认为该问题与在数据库中使用VARCHAR数据类型有关。如果where参数声明为NVARCHAR,则SQL Server似乎不使用指定的索引。

但是,您可以将数据库列更改为NVARCHAR(这会增加大小),然后索引性能可能会提高。

我目前正在使用LINQ这个问题,实际上可能需要恢复使用存储过程来解决它。

this Microsoft Connect discussion

详细说明了这个问题

答案 3 :(得分:0)

我会将查询移到存储过程,然后在命令中指定command.CommandType = CommandType.StoredProcedure。

这不会创建sp_executesql并提高性能