【发布时间】:2012-03-27 14:36:05
【问题描述】:
我经常遇到这样的情况:一个查询通过 SSMS 立即运行并进行少量读取,但速度慢到在通过 ADO.NET 运行时会因数千次读取而超时。 与我可以在 StackOverflow 上找到的其他问题不同,清除查询缓存(或强迫自己使用 SSMS 使用的那个)似乎没有奏效。
通常,当其他人在 StackOverflow 上报告这种情况时,他们的查询缓存已损坏。在所有这些情况下,修复方法是使用 SET ARITHABORT ON 运行 ADO.NET 查询(以匹配 SSMS 使用的会话设置)或运行 DBCC DROPCLEANBUFFERS 和 DBCC FREEPROCCACHE 以强制重建查询缓存.这些技术对我的应用程序没有任何影响,让我相信还有更基本的事情正在发生。
有问题的查询是这样的(由 SQL Profiler 捕获的实际逐字查询,仅为格式化而清理):
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,@p2=@p5
(XML 参数是为了允许使用参数化查询,而我通常会遇到麻烦,因为我要传入的对象数量会有所不同。表值过程将是 2008 年的方法,但我们的一些客户在 2005 年运行。)
通过 SSMS 运行,实际使用的查询计划看起来很合适(索引搜索),并且在 4 毫秒内需要大约 200 次读取。运行 Web 应用程序,每秒钟大约需要 4500 次读取。
我在这里缺少什么?尽管有DBCC 调用和ARITHABORT 设置,但在通过Web 应用程序运行时是否会恢复错误的查询计划?
【问题讨论】:
-
“这是一个典型的 use-XML-to-do-a-parameterized-WHERE IN-clause hack” - 再由我运行那个?
-
BTW:“在所有这些情况下,解决方法是在 SET ARITHABORT ON 的情况下运行 ADO.NET 查询(以匹配 SSMS 使用的会话设置)或运行 DBCC DROPCLEANBUFFERS 和DBCC FREEPROCCACHE 强制查询缓存重建”——这些都不是真正的修复。那是治标不治本。
-
@MitchWheat 我稍微清理了这个解释。此查询用
WHERE ixChangeset IN (...)子句中的任意、可能大量的元素替换了一个,允许对其进行参数化并命中查询缓存。 -
@MitchWheat 是的,我知道
DBCC之类的东西是治标不治本的,但我原本希望在 SSMS 中设置ARITHABORT OFF至少能给我错误的查询计划。可悲的是,情况似乎并非如此。 -
阅读 Erland Sommarskog(SQL Server MVP)撰写的这篇文章:应用程序慢,SSMS 快? (sommarskog.se/query-plan-mysteries.html)
标签: sql-server performance ssms