46

我正在尝试在我维护的 Web 应用程序中调试 SQL 超时的来源。我有后面的 C# 代码的源代码,所以我确切地知道正在运行什么代码。我已将应用程序调试到执行超时的 SQL 代码的行,并观察 SQL 探查器中运行的查询。

从 Web 执行此查询时,它会在 30 秒后超时。但是,当我完全按照 Profiler 中的方式剪切/粘贴查询并将其放入 SSMS 并运行它时,它几乎会立即返回。我已经将问题追溯到在网络正在使用的连接中将 ARITHABORT 设置为 OFF(也就是说,如果我在 SSMS 会话中将 ARITHABORT 关闭,它会运行很长时间,如果我将其重新打开,那么它会运行很快)。但是,阅读 ARITHABORT 的描述,它似乎并不适用......我只是在做一个简单的 SELECT,根本没有执行任何算术运算......只有一个带有 WHERE 条件的 INNER JOIN:

为什么 ARITHABORT OFF 在这种情况下会导致这种行为?有什么方法可以从 SSMS 更改该连接的 ARITHABORT 设置?我正在使用 SQL Server 2008。

4

8 回答 8

44

因此,您的 C# 代码正在使用什么方法向 SQL Server 发送一个即席 SQL 查询?您是否考虑过使用存储过程?无论是谁调用它,这都可能确保相同的性能(至少在引擎中)。

为什么?ARITHABORT 设置是优化器在确定如何执行查询(更具体地说,用于计划匹配)时查看的内容之一。缓存中的计划可能与 SSMS 具有相同的设置,因此它使用缓存的计划,但是使用相反的设置,您的 C# 代码会强制重新编译(或者您可能在缓存中遇到了一个非常糟糕的计划),这在很多情况下肯定会损害性能。

如果您已经在调用存储过程(您没有发布查询,尽管我认为您打算这样做),您可以尝试将 OPTION (RECOMPILE) 添加到存储过程中的有问题的查询(或多个查询)中。这将意味着这些语句将始终重新编译,但它可以防止使用您似乎遇到的错误计划。另一种选择是确保在编译存储过程时,使用 SET ARITHABORT ON 执行批处理。

最后,您似乎在问如何更改 SSMS 中的 ARITHABORT 设置。我认为您要问的是如何在代码中强制使用 ARITHABORT 设置。如果您决定继续从 C# 应用程序发送临时 SQL,那么您当然可以将命令作为文本发送,其中包含用分号分隔的多个语句,例如:

SET ARITHABORT ON; SELECT ...

有关此问题发生原因的详细信息,请参阅 Erland Sommarskog 的精彩文章:

于 2010-02-11T23:27:05.737 回答
17

此答案包括解决此问题的方法:

通过以管理员身份在数据库上运行以下命令,所有查询都会按预期运行,而不管 ARITHABORT 设置如何。

 DBCC DROPCLEANBUFFERS
 DBCC FREEPROCCACHE

更新

似乎大多数人最终很少遇到这个问题,而上述技术是一个不错的一次性修复。但是,如果一个特定的查询不止一次地出现这个问题,一个更长期的解决这个问题的方法是使用 Query HintsOPTIMIZE FOROPTION(Recompile),如 本文所述

更新 2

SQL Server 对其查询执行计划算法进行了一些改进,我发现这样的问题在新版本中越来越少见。如果您遇到此问题,您可能需要检查您正在执行的数据库上的兼容性级别设置(不一定是您要查询的数据库,而是默认数据库 - 或“InitialCatalog”)联系)。如果您停留在旧的兼容性级别,您将使用旧的查询执行计划生成技术,这些技术产生错误查询的可能性要高得多。

于 2011-10-06T15:53:01.233 回答
4

我以前多次遇到过这个问题,但是如果你有一个存储过程有同样的问题,那么删除并重新创建存储过程将解决这个问题。

这称为参数嗅探。您需要始终本地化存储过程中的参数以避免将来出现此问题。

我知道这可能不是原始海报想要的,但可能会帮助遇到同样问题的人。

于 2012-08-17T15:35:22.927 回答
1

如果使用实体框架,您必须知道字符串值的查询参数默认情况下作为 nvarchar 发送到数据库,如果要比较的数据库列类型为 varchar,根据您的排序规则,查询执行计划可能需要“隐式转换”步骤,即强制进行全面扫描。我可以通过查看昂贵查询选项中的数据库监控来确认它,该选项显示执行计划。

最后,在本文中对此行为进行解释: https ://www.sqlskills.com/blogs/jonathan/implicit-conversions-that-c​​ause-index-scans/

于 2018-07-20T22:59:14.623 回答
1

仅仅使用 ARITHABORT 并不能解决问题,特别是如果您使用参数化存储过程。

因为参数化存储过程会导致“参数嗅探”,它使用缓存的查询计划

因此,在得出结论之前,请检查以下链接。

The-elephant-and-the-mouse-or-parameter-sniffing-in-sql-server

于 2020-06-18T12:10:45.157 回答
0

我遇到了同样的问题,通过执行“WITH RECOMPILE”程序解决了这个问题。您也可以尝试使用参数嗅探。我的问题与 SQL 缓存有关。

于 2014-06-09T18:58:48.077 回答
0

如果您可以更改代码以修复参数嗅探,则优化未知提示是您的最佳选择。如果你不能改变你的代码,最好的选择是 exec sp_recompile 'name of proc',它只会强制那个存储的 proc 获得一个新的执行计划。删除和重新创建 proc 会产生类似的效果,但如果有人在您删除 proc 时尝试执行它,则可能会导致错误。DBCC FREEPROCCACHE 会丢弃所有缓存计划,这些计划可能会严重破坏您的系统,包括在繁重的事务生产环境中导致大量超时。设置 arithabort 不是解决问题的方法,而是发现参数嗅探是否是问题的有用工具。

于 2016-01-08T19:20:22.033 回答
0

我在尝试从 SMSS 调用 SP 时遇到了同样的问题,需要 2 秒,而从 webapp (ASP.NET) 调用 SP 大约需要 3 分钟。

我已经尝试了所有建议的解决方案sp_recompileDBCC FREEPROCCACHEDBCC DROPCLEANBUFFERS没有解决我的问题,但是当尝试参数嗅探时,它成功了,并且工作得很好。

于 2017-03-29T18:02:10.150 回答