首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使SqlClient默认为ARITHABORT

使SqlClient默认为ARITHABORT
EN

Database Administration用户
提问于 2011-05-03 16:17:54
回答 5查看 32.6K关注 0票数 38

首先要做的事情是:我将MS 2008与兼容级别为80的数据库一起使用,并与.NET的System.Data.SqlClient.SqlConnection连接。

出于性能原因,我创建了一个索引视图。因此,需要使用ARITHABORT ON对视图中引用的表进行更新。但是,分析器显示SqlClient与ARITHABORT OFF连接,因此对这些表的更新失败。

是否有使SqlClient使用ARITHABORT ON的中央配置设置?我所能找到的最好的方法是每次打开连接时手动执行,但是更新现有的代码库来完成这一任务将是一项相当大的任务,因此我渴望找到一种更好的方法。

EN

回答 5

Database Administration用户

发布于 2015-03-12 16:07:12

似乎是首选的方法

我的印象是,其他人已经对以下内容进行了测试,特别是根据一些评论。但我的测试表明,这两种方法确实在DB级别上工作,甚至在通过.NET SqlClient进行连接时也是如此。这些都经过了其他人的检验和验证。

服务器范围的

您可以将用户选项服务器配置设置设置为当前按位使用64的OR(ARITHABORT的值)。如果您不使用按位OR (|),而是执行直接赋值(=),那么您将删除任何其他已启用的现有选项。

代码语言:javascript
复制
DECLARE @Value INT;

SELECT @Value = CONVERT(INT, [value_in_use]) --[config_value] | 64
FROM   sys.configurations sc
WHERE  sc.[name] = N'user options';

IF ((@Value & 64) <> 64)
BEGIN
  PRINT 'Enabling ARITHABORT...';
  SET @Value = (@Value | 64);

  EXEC sp_configure N'user options', @Value;
  RECONFIGURE;
END;

EXEC sp_configure N'user options'; -- verify current state

Database-level

这可以通过改变数据库集设置为每个数据库:

代码语言:javascript
复制
USE [master];

IF (EXISTS(
     SELECT *
     FROM   sys.databases db
     WHERE  db.[name] = N'{database_name}'
     AND    db.[is_arithabort_on] = 0
   ))
BEGIN
  PRINT 'Enabling ARITHABORT...';

  ALTER DATABASE [{database_name}] SET ARITHABORT ON WITH NO_WAIT;
END;

交替逼近

不太好的消息是,我在这个主题上做了很多搜索,结果发现多年来有很多人在这个主题上做了大量的搜索,并且没有办法配置SqlClient的行为。一些MSDN文档意味着它可以通过ConnectionString完成,但是没有允许更改这些设置的关键字。另一个文档意味着它可以通过客户端网络配置/配置管理器进行更改,但这似乎也是不可能的。因此,更不幸的是,您需要手动执行SET ARITHABORT ON;。以下是一些考虑的方法:

如果使用的是实体框架6(或更新版本),可以尝试:

这将允许您在执行SQL之前修改它,在这种情况下,您可以简单地将其前缀为:SET ARITHABORT ON;。这里的缺点是,它将针对每个查询进行,除非您存储一个局部变量来捕获它是否已被执行的状态,并每次对其进行测试(这实际上并不是那么多额外的工作,但使用ExecuteSqlCommand可能更容易)。

这两种方法都允许您在不更改任何现有代码的情况下在一个地方处理这一问题。

否则,您可以创建一个包装器方法来执行此操作,类似于:

代码语言:javascript
复制
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
  CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;

  return CommandToExec.ExecuteReader();
}

然后只需将当前的_Reader = _Command.ExecuteReader();引用更改为_Reader = ExecuteReaderWithSetting(_Command);

这样做还允许在单个位置处理设置,同时只需要进行最小和简单的代码更改,这些更改大多可以通过查找和替换完成。

更好的是(其他第2部分),因为这是一个连接级别设置,因此不需要在每个SqlCommand.Execute__()调用中执行它。因此,与其为ExecuteReader()创建一个包装器,不如为Connection.Open()创建一个包装器:

代码语言:javascript
复制
public static void OpenAndSetArithAbort(SqlConnection MyConnection)
{
  using (SqlCommand _Command = MyConnection.CreateCommand())
  {
    _Command.CommandType = CommandType.Text;
    _Command.CommandText = "SET ARITHABORT ON;";

    MyConnection.Open();

    _Command.ExecuteNonQuery();
  }

  return;
}

然后将现有的_Connection.Open();引用替换为OpenAndSetArithAbort(_Connection);

以上两种思想都可以通过创建一个扩展SqlCommand或SqlConnection的类,以更多的面向对象的方式实现。

或者更好的是(其他第3部分),您可以为连接StateChange创建一个事件处理程序,并让它在连接从Closed更改为Open时设置该属性,如下所示:

代码语言:javascript
复制
protected static void OnStateChange(object sender, StateChangeEventArgs args)
{
    if (args.OriginalState == ConnectionState.Closed
        && args.CurrentState == ConnectionState.Open)
    {
        using (SqlCommand _Command = ((SqlConnection)sender).CreateCommand())
        {
            _Command.CommandType = CommandType.Text;
            _Command.CommandText = "SET ARITHABORT ON;";

            _Command.ExecuteNonQuery();
        }
    }
}

这样,您只需要在创建SqlConnection实例的每个地方添加以下内容:

代码语言:javascript
复制
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);

不需要对现有代码进行更改。我刚刚在一个小型控制台应用程序中尝试了这种方法,通过打印SELECT SESSIONPROPERTY('ARITHABORT');的结果进行测试。它返回1,但如果禁用事件处理程序,则返回0

为了完整起见,以下是一些不起作用的东西(要么根本不起作用,要么不那么有效):

  • 登录触发器:触发器,即使在同一会话中运行,即使在显式启动的事务中运行,仍然是子进程,因此它的设置(SET命令、本地临时表等)是本地的,在子进程结束时不能存活。
  • SET ARITHABORT ON;添加到每个存储过程的开头:
    • 这需要对现有项目进行大量的工作,特别是随着存储过程数量的增加。
    • 这无助于临时查询。
票数 37
EN

Database Administration用户

发布于 2015-03-09 14:46:36

选项1

除了桑卡尔解决方案之外,在服务器级别设置所有连接的算术中止设置都可以:

代码语言:javascript
复制
EXEC sys.sp_configure N'user options', N'64'
GO
RECONFIGURE WITH OVERRIDE
GO

截至2014年,所有连接都是建议上

在登录会话中,应该始终将ARITHABORT设置为ON。将ARITHABORT设置为OFF会对查询优化产生负面影响,从而导致性能问题。

因此,这似乎是理想的解决方案。

选项2

如果选项1不可行,并且在大多数SQL调用中使用存储过程(请参见存储过程与内联SQL),那么只需在每个相关存储过程中启用该选项:

代码语言:javascript
复制
CREATE PROCEDURE ...
AS 
BEGIN
   SET ARITHABORT ON
   SELECT ...
END
GO

我相信这里最好的真正解决方案就是简单地编辑您的代码,因为它是错误的,而且任何其他的修复都只是一个解决办法。

票数 6
EN

Database Administration用户

发布于 2011-05-03 17:15:30

我不是这里的专家,但你可以试试下面这样的方法。

代码语言:javascript
复制
String sConnectionstring;
sConnectionstring = "Initial Catalog=Pubs;Integrated Security=true;Data Source=DCC2516";

SqlConnection Conn = new SqlConnection(sConnectionstring);

SqlCommand blah = new SqlCommand("SET ARITHABORT ON", Conn);
blah.ExecuteNonQuery();


SqlCommand cmd = new SqlCommand();
// Int32 rowsAffected;

cmd.CommandText = "dbo.xmltext_import";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = Conn;
Conn.Open();
//Console.Write ("Connection is open");
//rowsAffected = 
cmd.ExecuteNonQuery();
Conn.Close();

参考文献:http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/d9e3e8ba-4948-4419-bb6b-dd5208bd7547/

票数 4
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/2500

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档