首先要做的事情是:我将MS 2008与兼容级别为80的数据库一起使用,并与.NET的System.Data.SqlClient.SqlConnection连接。
出于性能原因,我创建了一个索引视图。因此,需要使用ARITHABORT ON对视图中引用的表进行更新。但是,分析器显示SqlClient与ARITHABORT OFF连接,因此对这些表的更新失败。
是否有使SqlClient使用ARITHABORT ON的中央配置设置?我所能找到的最好的方法是每次打开连接时手动执行,但是更新现有的代码库来完成这一任务将是一项相当大的任务,因此我渴望找到一种更好的方法。
发布于 2015-03-12 16:07:12
我的印象是,其他人已经对以下内容进行了测试,特别是根据一些评论。但我的测试表明,这两种方法确实在DB级别上工作,甚至在通过.NET SqlClient进行连接时也是如此。这些都经过了其他人的检验和验证。
您可以将用户选项服务器配置设置设置为当前按位使用64的OR(ARITHABORT的值)。如果您不使用按位OR (|),而是执行直接赋值(=),那么您将删除任何其他已启用的现有选项。
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这可以通过改变数据库集设置为每个数据库:
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(或更新版本),可以尝试:
context.Database.ExecuteSqlCommand("SET ARITHABORT ON;"); ,理想情况下,这将在打开DB连接之后执行一次,而不是每个查询。这将允许您在执行SQL之前修改它,在这种情况下,您可以简单地将其前缀为:SET ARITHABORT ON;。这里的缺点是,它将针对每个查询进行,除非您存储一个局部变量来捕获它是否已被执行的状态,并每次对其进行测试(这实际上并不是那么多额外的工作,但使用ExecuteSqlCommand可能更容易)。
这两种方法都允许您在不更改任何现有代码的情况下在一个地方处理这一问题。
否则,您可以创建一个包装器方法来执行此操作,类似于:
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()创建一个包装器:
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时设置该属性,如下所示:
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实例的每个地方添加以下内容:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);不需要对现有代码进行更改。我刚刚在一个小型控制台应用程序中尝试了这种方法,通过打印SELECT SESSIONPROPERTY('ARITHABORT');的结果进行测试。它返回1,但如果禁用事件处理程序,则返回0。
为了完整起见,以下是一些不起作用的东西(要么根本不起作用,要么不那么有效):
SET命令、本地临时表等)是本地的,在子进程结束时不能存活。SET ARITHABORT ON;添加到每个存储过程的开头:发布于 2015-03-09 14:46:36
除了桑卡尔解决方案之外,在服务器级别设置所有连接的算术中止设置都可以:
EXEC sys.sp_configure N'user options', N'64'
GO
RECONFIGURE WITH OVERRIDE
GO截至2014年,所有连接都是建议上:
在登录会话中,应该始终将ARITHABORT设置为ON。将ARITHABORT设置为OFF会对查询优化产生负面影响,从而导致性能问题。
因此,这似乎是理想的解决方案。
如果选项1不可行,并且在大多数SQL调用中使用存储过程(请参见存储过程与内联SQL),那么只需在每个相关存储过程中启用该选项:
CREATE PROCEDURE ...
AS
BEGIN
SET ARITHABORT ON
SELECT ...
END
GO我相信这里最好的真正解决方案就是简单地编辑您的代码,因为它是错误的,而且任何其他的修复都只是一个解决办法。
发布于 2011-05-03 17:15:30
我不是这里的专家,但你可以试试下面这样的方法。
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/
https://dba.stackexchange.com/questions/2500
复制相似问题