为什么 SET ARITHABORT ON 会显着加快查询速度?

Jon*_*len 88 sql-server

查询是包含许多分组级别和聚合操作的单个选择。使用 SET ARITHABORT ON 只需不到一秒钟,否则需要几分钟。我们已经在 SQL Server 2000 和 2008 上看到了这种行为。

小智 71

有点过时了,但是对于最终遇到类似问题的任何人...

我有同样的问题。对我来说,结果是参数嗅探,一开始我并没有足够的了解来关心它。我添加了一个 'set arithabort on' 来解决这个问题,但后来又回来了。然后我读到:

http://www.sommarskog.se/query-plan-mysteries.html

它清除了一切。因为我使用的是 Linq to SQL 并且解决问题的选项有限,所以我最终使用了查询计划指南(参见链接末尾)来强制执行我想要的查询计划。

  • 六年多后,这个答案中给出的链接仍然是“必读”......而且仍然是最新的,最新修订版是 17 年 12 月。 (5认同)

小智 32

.NET 应用程序连接时默认禁用该选项,但它在 Management Studio 中默认启用。结果是服务器实际上为大多数/所有过程缓存了 2 个单独的执行计划。这会影响服务器执行数值计算的方式,因此您可以根据程序获得截然不同的结果。这实际上只是 proc 可以得到糟糕的执行计划的两种常见方式之一,另一种是参数嗅探。

看看https://web.archive.org/web/20150315031719/http://sqladvice.com/blogs/gstark/archive/2008/02/12/Arithabort-Option-Effects-Stored-Procedure-Performance。 aspx进行更多讨论。

  • @Martin:我想我不清楚。我只是说 ARITHABORT ON 会使 SQL Server 在出现任何 div/0 或算术溢出错误时出错。当它关闭时,它会继续运行,无论出于何种原因都会导致各种可怕的问题。 (2认同)
  • @Ben - 是的,抱歉,我不想特别攻击你的答案,我只是指出,更改“SET”选项会很容易获得更好的计划,并将其误诊为选项本身有问题。我不相信你链接中的那个人没有这样做。 (2认同)

Mar*_*ith 23

我认为这几乎可以肯定是参数嗅探。

人们经常说这SET OPTIONS会以这种方式影响性能,但我还没有看到这个声明的单一权威来源,除了您使用索引视图/持久计算列的情况。

在这种情况下(对于 SQL2005+,除非您的数据库处于 SQL2000 兼容模式)。如果两者都有ARITHABORTANSI_WARNINGS OFF那么你会发现索引没有被使用,所以可能有一个扫描而不是所需的搜索(以及一些开销,因为无法使用持久计算结果)。ADO.NET 似乎默认使用ANSI_WARNINGS ON我刚刚进行的快速测试。

该要求在Ben的回答说,“这样的服务器进行数值计算”可以添加分钟,否则将需要不到一个结果第二似乎没有可信的我。我认为往往会发生的是,在调查性能性能问题时,使用 Profiler 来识别有问题的查询。这被粘贴到管理工作室并运行并立即返回结果。连接之间唯一明显的区别是ARITH_ABORT选项。

在管理工作室窗口中进行的快速测试表明,当SET ARITHABORT OFF打开并运行查询时,性能问题会再次出现,因此显然已关闭案例。事实上,这似乎是Gregg Stark链接中使用的故障排除方法。

然而,这忽略了这样一个事实,即设置了该选项后,您最终可能会从缓存中获得完全相同的错误计划。

即使您以与应用程序连接使用的用户不同的用户身份登录,也可能会发生此计划重用。

我通过首先从 Web 应用程序然后从管理工作室执行测试查询来测试这个,SET ARITHABORT OFF并且可以看到使用计数从下面的查询中上升。

SELECT usecounts, cacheobjtype, objtype, text ,query_plan
FROM sys.dm_exec_cached_plans 
CROSS APPLY sys.dm_exec_sql_text(plan_handle) 
CROSS APPLY sys.dm_exec_query_plan(plan_handle) 
Run Code Online (Sandbox Code Playgroud)

为了实际发生这种共享 pf 计划,所有计划缓存键必须相同。与arithabort它本身一样,其他一些示例是执行用户需要相同的默认模式(如果查询依赖于隐式名称解析)并且连接需要相同的language设置。

更完整的计划缓存键列表在这里


mdo*_*yle 16

我知道我参加这个派对迟到了,但对于未来的访客来说,马丁是完全正确的。我们遇到了同样的问题——一个 SP 在 .NET 客户端上运行得非常慢,而对于 SSMS 来说它运行得非常快。在探索和解决问题的过程中,我们进行了 Kenny Evitt 在对 Martin 问题的评论中提出的系统测试。

使用 Martin 查询的变体,我在过程缓存中查找 SP 并找到其中两个。从计划来看,实际上是这样一种情况,一个是开启了 ARITHABORT,一个是关闭了 ARITHABORT。ARITHABORT OFF 版本有一个索引搜索,而 ARITHABORT ON 版本对相同的输出使用索引扫描。考虑到所涉及的参数,索引查找将需要在数千万条记录中查找输出。

我从缓存中清除了这两个过程,并让 .NET 客户端再次运行 SP,使用相同的参数(对于具有大量活动的客户而言,该参数具有广泛的日期范围)。SP立即返回。缓存计划使用了以前在 ARITHABORT ON 计划中使用的相同索引扫描——但这次计划是针对 ARITHABORT OFF 的。我们在 SSMS 中使用相同的参数运行 SP,再次立即得到结果。现在我们看到第二个计划被缓存,用于 ARITHABORT ON,与索引扫描。

然后我们清除了缓存,在 SSMS 中运行了一个日期范围很窄的 SP 并立即得到了结果。我们发现生成的缓存计划有一个索引搜索,因为相同的输出以前是用扫描处理的(这也是 ARITHABORT 关闭的原始计划中的搜索)。再次从 SSMS 中,我们运行了 SP,这次具有相同的广泛日期范围,并且看到了与原始 .NET 请求中同样糟糕的性能。

简而言之,这种差异与 ARITHABORT 的实际值无关——无论是打开还是关闭,无论是从哪个客户端,我们都可以获得可接受或糟糕的性能:所有重要的是用于编译和缓存计划的参数值。

虽然MSDN表明 ARITHABORT OFF 本身可能对查询优化产生负面影响,但我们的测试证实 Martin 是正确的——原因是参数嗅探,结果计划对所有参数范围都不是最优的。