2012-03-27 37 views
4

我处于常年的状况:通过少量读取即可通过SSMS即时运行的查询,但运行速度足以在运行时读取数千个读取通过ADO.NET。 不同,我可以在StackOverflow上找到的其他问题,清除查询缓存(或者强迫自己使用一个SSMS使用)似乎没有什么用。基于XML的查询通过ADO.NET非常缓慢,即时通过SSMS

通常,当其他人在StackOverflow中报告了这种情况时,他们已经损坏了查询缓存。在所有这些情况下,修复程序或者运行ADO.NET查询SET ARITHABORT ON(与SSMS使用的会话设置相匹配),或者运行DBCC DROPCLEANBUFFERSDBCC FREEPROCCACHE强制查询缓存重建。这些技术在我的应用程序中没有任何区别,这让我相信有更基础的事情发生。

有问题的查询是这样的(由SQL事件探查器捕获实际逐字查询,仅用于格式化清理):

declare @p5 xml 
set @p5=convert(xml,N'<r> 
<n v="66ebc21b3bcb31e9a5ecbfb4b29fd2a47c37994c"/> 
<n v="665919306fb23d9e685638a2d199e1e623745305"/> 
<n v="a080c3b4e0c86e37b4d494d5efc09cebe20c6929"/> 
<n v="245cb49bdeca9e37ef9bbd55877e21ade14e6282"/> 
<n v="297650a6be65be332c1bb2aab426331a156ee342"/> 
<n v="6a2668c8ab64fecf3b6925c7be613c61cef4dd7c"/> 
<n v="09923f25f8b1de19f693bca1111bfa50d617856e"/> 
<n v="0a7836d8e4e34f4ea92b2105eea5a99029949428"/></r>') 
exec sp_executesql N' 
      SELECT ixChangesetTag, ixRepo, ixChangeset, sTag, fBookmark 
      FROM ChangesetTag 
       INNER JOIN @p2.nodes(''/r/n'') X(n) ON X.n.value(''xs:hexBinary(@v)'', ''binary(20)'') = ixChangeset 
      WHERE ixRepo = @p0 AND ixCustomer = @p1',N'@p0 bigint,@p1 int,@p2 xml',@p0=2,@p1=23363,@[email protected] 

(XML参数是为了让使用参数化查询,我会通常会遇到麻烦,因为我想要通过的对象数量是不同的。表值程序将是2008年的方式,但我们的一些客户在2005年运行。)

通过SSMS运行使用的实际查询计划看起来合适(索引查找),并且在4ms以上需要大约200次读取。通过Web应用程序运行,每秒大约需要4500次读取。

我在这里错过了什么?尽管有DBCC调用和ARITHABORT设置,但是在通过Web应用程序运行时是否可以恢复错误的查询计划?

+0

“这是一个典型的使用-XML-to-do-a-parameterized-WHERE IN-clause hack” - 再次运行一个? – 2012-03-27 14:38:46

+0

顺便说一下:“在所有这些情况下,修复程序或者是使用SET ARITHABORT ON运行ADO.NET查询(以匹配SSMS使用的会话设置),或者运行DBCC DROPCLEANBUFFERS和DBCC FREEPROCCACHE来强制查询缓存重建“ - 这些都没有实际修复。这是治疗症状,而不是真正的原因。 – 2012-03-27 14:39:36

+0

@MitchWheat我清理了这个解释。这个查询用'WHERE ixChangeset IN(...)'子句中的任意可能大量的元素替换了一个元素,从而允许它被参数化并击中查询缓存。 – 2012-03-27 14:45:23

回答

1

问题最终导致SQL Server通常选择一个绝对可怕的执行策略,基本上循环遍历XML,而不是做一个理智的加入。修正是将XML放入临时表中,并加入而不是,这可靠地产生了良好的执行计划。

1

简单解决方法是在(ixCustomer,ixRepo,ixChangeset)上放置多列索引。不知道列的实际内容,它们是否独特等等,很难得出更好的答案。

+0

鉴于查询从SSMS运行时立即运行,我不愿相信这是一个索引问题。 – 2012-03-27 16:16:20

+0

@Benjamin Pollack - 当你从SMS运行时,它会选择一个更好的索引,然后当你从代码运行时,可能会做一些模棱两可的字符集设置或.NET的不同,然后默认的SMS会话。如果你做多列索引,它总是倾向于使用它。 – 2012-03-27 16:51:25