在我们的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具有a
,b
的实际值以及所有其他可用参数,并且可以使用统计信息来创建更好的计划。显然,参数的具体值的查询计划比通用的好得多,绝对超过任何“查询计划缓存”性能优势。
现在我的问题:在执行参数化查询时,ADO.NET似乎总是使用第二个选项(sp_executesql),通常有意义(查询计划缓存等)。然而,在我们的案例中,这会导致性能下降。那么,有没有办法
sp_executesql
不同的内容(即SQL Server查询分析器将实际参数值考虑在内的内容)或sp_executesql
的SQL的查询计划,并将参数值考虑在内?请不要告诉我,我必须回到丑陋,陈旧,危险的sql = "WHERE b = " + quoteAndEscape(parameterB)
......
将SQL放入存储过程没有任何区别(慢,有和没有WITH RECOMPILE
)。我没有发布实际的SQL语句,因为它非常复杂(连接多个表,包括子SELECT和聚合)。
答案 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这个问题,实际上可能需要恢复使用存储过程来解决它。
详细说明了这个问题答案 3 :(得分:0)
我会将查询移到存储过程,然后在命令中指定command.CommandType = CommandType.StoredProcedure。
这不会创建sp_executesql并提高性能