【问题标题】:C# SqlCommand.ExecuteNonQuery() and SQL SET NOCOUNT ONC# SqlCommand.ExecuteNonQuery() 和 SQL SET NOCOUNT ON
【发布时间】:2018-09-17 15:27:29
【问题描述】:

我已经搜索了整个下午,但我不认为这与像 ExecuteNonQuery() and SET NOCOUNT ON 这样的其他问题重复。

我还发现了一个关于 Finding code smells using SQL Prompt: the SET NOCOUNT problem (PE008 and PE009) 的有趣博客,其中包含了一些有趣的细节,但仍然没有回答我的问题。

我有一个数据库服务器,管理员在其中勾选了服务器连接的 no count 选项(在 SSMS 中,右键单击对象资源管理器中的服务器,转到属性,选择连接页面,在“默认连接选项”下,向下滚动直到找到“无计数”选择器)。

根据我所做的所有阅读,越来越多的管理员可能会勾选no count 选项以提高性能,因为结果行将不再发送回客户端。

因此,我的问题主要集中在 C# 中的 SqlCommand.ExecuteNonQuery Method 上,因为它依赖于以下事实:

针对连接执行 Transact-SQL 语句并返回受影响的行数

但如果强制执行SET NOCOUNT ON,则结果将始终为-1。我已经阅读了人们如何推荐而不是使用select @rowcount = @@ROWCOUNT 但这并不能弥补您从SqlCommand.ExecuteNonQuery 方法中失去功能的事实,以至于您不妨开始使用SqlCommand.ExecuteScalar而是。

所以我的问题是,为了获得最佳实践,我们是否应该开始将 SQL Server 设置为 no count(或者至少期望他们将在接下来的几年内开始配置它们),然后如果是这样,我们应该强制SET NOCOUNT OFF 还是放弃SqlCommand.ExecuteNonQuery 以支持select @rowcount = @@ROWCOUNT

【问题讨论】:

  • 我很确定没有 no count 选项这样的东西。有SET NOCOUNT ON,第三方产品中可能有一个选项,相当于“当我检查这个时自动发出SET NOCOUNT ON”(Management Studio 有这样一个选项),但是没有 SQL Server 默认值(嗯,@987654337 @ 是默认值)。存储过程通常以SET NOCOUNT ON 开头,但这是另一回事。这个no count 选项应该在哪里管理员勾选?
  • 换一种说法,如果你给数据库设置了一个SqlConnection(没有特殊关键字),然后你发出一个SqlCommand,上面写着DECLARE @T TABLE(ID INT); INSERT @T DEFAULT VALUES,那么ExecuteNonQuery是什么意思?给你?无论任何 SQL Server 设置如何,它都应该是1。换句话说,SET NOCOUNT 仍然是执行查询的选择。
  • 啊,等等,我错了! 一种将NOCOUNT ON 设为默认值的方法,它涉及调用sp_configure 'user options', 512。 (我的 Management Studio 版本没有用于此的 UI,但我想某些版本可能。)在此之后,您确实会观察到 NOCOUNT 有效,并且所有 ExecuteNonQuery 调用都给出 -1,除非明确的 SET NOCOUNT OFF首先发出。就像出厂默认设置的任何更改会更改 SQL 语义一样,我强烈建议不要这样做,无论声称的收益如何——开发人员不会期望它。
  • 对于“最佳实践”,我想说:如果您需要计数,请使用 either 目标 SET NOCOUNT OFF@@ROWCOUNT ,正如您认为合适的那样——一个并不比另一个优越。但相反,在服务器端,最佳实践是保留连接默认值,以便写入默认值(大部分)的软件不会无缘无故地中断。我怀疑是否有人彻底测试了实际的性能提升,并将其与更改软件的成本进行了比较,包括您的管理员。在 SQL Server 上要优化的所有内容中,NOCOUNT 的排名靠后。
  • 谢谢,我发现了。现在我知道如何更改默认值,我知道我永远不会做额外的内容。在任何服务器上。尽管我真的不介意,例如,从可管理性的角度来看,XACT_ABORT 默认为ON,但破坏软件的风险太大,并且不会超过潜在的好处。您可以该死确定,只要 SQL Server 继续支持某个选项,Microsoft 也不会触及这些默认值——当然不会NOCOUNT

标签: c# sql-server nocount


【解决方案1】:

大约十年前,我开始使用 SqlCop,它曾经突出显示“没有 SET NOCOUNT ON 的程序”。随着时间的推移,我已经进化,所以我不再使用它,但我喜欢这个概念,所以我有一组单元测试,它们运行元数据查询来查找像 SqlCop 用来突出显示的东西(以及更多)。

我的每个测试都允许我为每个规则添加排除项,这样我就可以在评论中记录排除它的理由。

我目前对此的测试(我不必亲自动手)可能会突出显示包含SELECT 但不包含SET NOCOUNT ON 的存储过程。这样,INSERTs、UPDATEs 和 DELETEs 都保留了默认行为,允许我的代码使用 ExecuteNonQuery 的结果。任何边缘情况都可以从规则中排除。

这让我可以让 SQL Server 保持默认行为,并且我的应用程序的 SP 可以选择何时改变 Microsoft 的默认设置。

请注意,如果有人修改了默认设置,那么我的代码将无法运行,因为我没有遵循 RedGate 文章末尾的建议“如果您需要确保查询返回行计数消息,您应该指定它而不是假定当前设置。".

这是非常明智的建议,因为事后诸葛亮是一件好事:如果您知道可以更改默认值,您只会知道需要设置它。有点像您了解到将 SP 脚本编写为“IF EXISTS、DROP 和 CREATE”(SSMS 提供了有帮助)是一种愚蠢的做法:最好只 IF NOT EXISTS 创建一个占位符,并且然后将其更改为实际定义(避免丢失元数据,如权限)。

当然,我可以修复我的 SP,并添加新的或更改的单元测试以确保我始终以一种或另一种方式设置 NOCOUNT 选项。但我要说的一点是,如果将这种行为设置为不同于默认值也可能会破坏您在该服务器上安装的任何第三方产品,我不会感到惊讶。 (也许这在您的场景中并不重要。)

无论您决定采用哪种方式,我只是觉得这种通过单元测试来执行您决定的方法的技术非常宝贵。检查它是否总是由每个 SP 设置为一种或另一种方式似乎是明智的。

【讨论】:

  • 谢谢你,我的主要问题仍然是关于 SqlCommand.ExecuteNonQuery 的未来是什么。如果我们迁移到@@ROWCOUNT,那么它真的会过时。我想我希望得到一个更接近实际做出决定的人而不是我们的意见的答案。如果有的话,是否应该更改 SqlCommand.ExecuteNonQuery 以使用 @@ROWCOUNT 代替?
  • 恐怕,“what's the future of” 将是基于意见的。事实上,经过反思,问题本身是基于意见的,这是vote-to-close-worthy。 NOCOUNT 的默认值当前具有特定值。改变它将是一个重大的改变(这是我试图在这里提出的观点)。所以我的观点是微软不会很快改变这个默认值。
  • 我听到你在说什么,我同意,但是我也看到了内部人员的回复,他们确切地知道 MS 在做什么(比如在 C# 语言团队中),我经常看到信息关于他们正在计划什么或为什么他们决定做某事。因此,我的问题旨在让更接近主题的人启发我们。希望这是有道理的。
  • @Storm: My question is therefore aimed at getting someone closer to subject to enlighten us ;那为什么要发在这里呢?看到这个答案,提前知道会为某人节省很多时间。尽管如此,这个答案非常有意义:除非必须,否则不要破坏默认值。
  • @Stefan,我应该在哪里发帖?
猜你喜欢
  • 2015-06-23
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 2011-10-10
  • 1970-01-01
  • 2012-05-30
  • 2013-07-23
  • 1970-01-01
相关资源
最近更新 更多