Pet*_*lor 34 sql-server-2008 sql-server ado.net configuration compatibility-level
首先要做的事情是:我将 MS SQL Server 2008 与兼容级别为 80 的数据库一起使用,并使用 .Net 的System.Data.SqlClient.SqlConnection.
出于性能原因,我创建了一个索引视图。因此,视图中引用的表的更新需要使用ARITHABORT ON. 但是,探查器显示 SqlClient 正在连接ARITHABORT OFF,因此对这些表的更新失败。
是否有使 SqlClient 使用的中央配置设置ARITHABORT ON?我能找到的最好方法是在每次打开连接时手动执行该操作,但是更新现有代码库以执行此操作将是一项相当大的任务,因此我很想找到更好的方法。
Sol*_*zky 32
我的印象是以下内容已经被其他人测试过,特别是基于一些评论。但我的测试表明,这两种方法确实在 DB 级别工作,即使通过 .NET 连接时也是如此SqlClient。这些已经过其他人的测试和验证。
服务器范围
您可以将用户选项服务器配置设置设置为当前OR使用 64( 的值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
Run Code Online (Sandbox Code Playgroud)
数据库级
这可以通过ALTER DATABASE SET为每个数据库设置:
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;
Run Code Online (Sandbox Code Playgroud)
不太好的消息是我在这个话题上做了很多搜索,才发现这些年来很多人在这个话题上做了很多搜索,并且没有办法配置行为的SqlClient。一些 MSDN 文档暗示它可以通过 ConnectionString 完成,但没有允许更改这些设置的关键字。另一个文档暗示它可以通过客户端网络配置/配置管理器进行更改,但这似乎也不可能。因此,不幸的是,您需要SET ARITHABORT ON;手动执行。这里有一些方法可以考虑:
如果您使用的是实体框架 6(或更新版本),您可以尝试:
使用Database.ExecuteSqlCommand:context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
理想情况下,这将在打开数据库连接后执行一次,而不是每个查询。
通过以下任一方式创建拦截器:
这将允许你修改在执行之前的SQL,在这种情况下,你可以简单地使用前缀:SET ARITHABORT ON;。这里的缺点是它将针对每个查询,除非您存储一个局部变量来捕获它是否已执行的状态并每次都对其进行测试(这确实没有那么多额外的工作,但使用的ExecuteSqlCommand是可能更容易)。
这两者中的任何一个都可以让您在不更改任何现有代码的情况下在一个地方处理此问题。
ELSE,您可以创建一个包装方法来执行此操作,类似于:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
Run Code Online (Sandbox Code Playgroud)
然后只需将当前_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;
}
Run Code Online (Sandbox Code Playgroud)
然后只需将现有_Connection.Open();引用替换为OpenAndSetArithAbort(_Connection);.
通过创建一个扩展 SqlCommand 或 SqlConnection 的类,以上两种想法都可以以更面向对象的方式实现。
或者更好(其他第 3 部分),您可以为 Connection 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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
有了它,您只需将以下内容添加到您创建SqlConnection实例的每个位置:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Run Code Online (Sandbox Code Playgroud)
无需更改现有代码。我刚刚在一个小型控制台应用程序中尝试了这种方法,通过打印SELECT SESSIONPROPERTY('ARITHABORT');. 它返回1,但如果我禁用事件处理程序,它返回0。
为了完整起见,这里有一些不起作用的东西(不管是完全有效还是无效):
SET命令、本地临时表等)是它的本地设置并且不会存活该子过程的结束。SET ARITHABORT ON;到每个存储过程的开头:
除了Sankar 的解决方案,在服务器级别为所有连接设置算术中止设置将起作用:
EXEC sys.sp_configure N'user options', N'64'
GO
RECONFIGURE WITH OVERRIDE
GO
Run Code Online (Sandbox Code Playgroud)
您应该始终在登录会话中将 ARITHABORT 设置为 ON。将 ARITHABORT 设置为 OFF 会对查询优化产生负面影响,从而导致性能问题。
所以这似乎是理想的解决方案。
如果选项 1 不可行并且您对大多数 SQL 调用使用存储过程(您应该这样做,请参阅存储过程与内联 SQL),然后只需在每个相关存储过程中启用该选项:
CREATE PROCEDURE ...
AS
BEGIN
SET ARITHABORT ON
SELECT ...
END
GO
Run Code Online (Sandbox Code Playgroud)
我相信这里最好的真正解决方案是简单地编辑您的代码,因为它是错误的,任何其他修复都只是一种解决方法。
我不是这里的专家,但你可以尝试如下所示的方法。
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();
Run Code Online (Sandbox Code Playgroud)