我正在尝试在我维护的Web应用程序中调试SQL超时的来源。我有C#代码的源代码,所以我确切地知道正在运行什么代码。我已经将应用程序调试到执行超时的SQL代码的行,并且我在SQL分析器中观察运行的查询。
当此查询从Web执行时,它会在30秒后超时。但是,当我完全按照Profiler中显示的方式剪切/粘贴查询时,我将其放入SSMS并运行它,它几乎立即返回。我已经跟踪了ARITHABORT在Web正在使用的连接中设置为OFF的问题(也就是说,如果我在SSMS会话中关闭ARITHABORT,它会运行很长时间,如果我将其重新打开,那么它会运行很快)。但是,阅读ARITHABORT的描述,它似乎并不适用......我只做一个简单的SELECT,并且根本没有执行任何算法......只有一个带有WHERE条件的INNER JOIN:
为什么ARITHABORT OFF会在此上下文中导致此行为?有什么办法可以改变SSMS对该连接的ARITHABORT设置吗?我正在使用SQL Server 2008。
那么您的C#代码是使用什么方法向SQL Server发送临时SQL查询?您考虑过使用存储过程吗?这可能会确保相同的性能(至少在引擎中),无论谁调用它。
为什么? ARITHABORT设置是优化程序在确定如何执行查询(更具体地说,用于计划匹配)时查看的内容之一。缓存中的计划可能与SSMS具有相同的设置,因此它使用缓存的计划,但是使用相反的设置,您的C#代码正在强制重新编译(或者您可能正在缓存中遇到真正的BAD计划),在很多情况下肯定会损害性能。
如果您已经在调用存储过程(虽然我认为您没有发布查询,但您可以尝试将OPTION(RECOMPILE)添加到存储过程中的违规查询(或查询)中。这将意味着这些语句将始终重新编译,但它可能会阻止使用您似乎遇到的糟糕计划。另一个选项是确保在编译存储过程时,使用SET ARITHABORT ON执行批处理。
最后,您似乎在询问如何更改SSMS中的ARITHABORT设置。我想您要问的是如何在代码中强制使用ARITHABORT设置。如果您决定继续从C#app发送临时SQL,那么当然您可以发送一个命令作为具有由分号分隔的多个语句的文本,例如:
SET ARITHABORT ON; SELECT ...
有关此问题发生原因的更多信息,请参阅Erland Sommarskog的精彩文章:
This answer包含解决此问题的方法:
通过在数据库上以管理员身份运行以下命令,无论ARITHABORT设置如何,所有查询都按预期运行。
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
似乎大多数人最终很少发生这个问题,而上述技术是一个体面的一次性修复。但是如果一个特定的查询不止一次地表现出这个问题,那么这个问题的一个更长期的解决方案就是使用Qazxswpoi和OPTIMIZE FOR
等查询提示,如OPTION(Recompile)
中所述。
我之前已经多次遇到过这个问题,但是如果你有一个存储过程同样的问题,那么丢弃并重新创建存储过程将解决问题。
它被称为参数嗅探。您需要始终本地化存储过程中的参数,以避免将来出现此问题。
我知道这可能不是原始海报想要的,但可能会帮助有同样问题的人。
如果使用Entity Framework,您必须知道字符串值的查询参数默认情况下以nvarchar的形式发送到数据库,如果要比较的数据库列是typed varchar,根据您的排序规则,查询执行计划可能需要“IMPLICIT CONVERSION”步骤,强制全扫描。我可以通过在昂贵的查询选项中查看数据库监视来确认它,该选项显示执行计划。
最后,在本文中对此行为进行了解释:this article
我有同样的问题,它通过执行程序“WITH RECOMPILE”修复。您也可以尝试使用参数嗅探。我的问题与SQL缓存有关。
如果您可以更改代码以修复参数嗅探优化未知提示是您的最佳选择。如果你不能改变你的代码,那么最好的选择就是exec sp_recompile'proc of proc',这将强制只有一个存储过程获得一个新的执行计划。删除和重新创建一个proc会产生类似的效果,但如果有人在你删除它时尝试执行proc,可能会导致错误。 DBCC FREEPROCCACHE会删除所有缓存的计划,这些计划可能会严重破坏您的系统,包括在繁重的交易生产环境中造成大量超时。设置arithabort不是问题的解决方案,但它是一个有用的工具,用于发现参数嗅探是否是问题。
我尝试从SMSS调用SP花了2秒时遇到同样的问题,而从webapp(ASP.NET)开始花了大约3分钟。
我已经尝试了所有建议的解决方案https://www.sqlskills.com/blogs/jonathan/implicit-conversions-that-cause-index-scans/,sp_recompile
和DBCC FREEPROCCACHE
,但没有解决我的问题,但当尝试参数嗅探它做了伎俩,并且工作得很好。