まず最初に、互換性レベル80のデータベースでMS SQL Server 2008を使用し、.NetのSystem.Data.SqlClient.SqlConnection
を使用してそれに接続しています。
パフォーマンス上の理由から、インデックス付きビューを作成しました。その結果、ビューで参照されるテーブルへの更新はARITHABORT ON
で行う必要があります。ただし、プロファイラーはSqlClientがARITHABORT OFF
で接続していることを示しているため、これらのテーブルへの更新は失敗しています。
SqlClientでARITHABORT ON
を使用するための中央構成設定はありますか?私が見つけた最高の方法は、接続が開かれるたびに手動で実行することですが、これを行うために既存のコードベースを更新するのはかなり大きなタスクになるため、より良い方法を見つけたいと思っています。
特に、いくつかのコメントに基づいて、以下はすでに他の人によってテストされているという印象を受けました。しかし、私のテストでは、.NET SqlClient
経由で接続している場合でも、これら2つの方法が実際にDBレベルで機能することが示されています。 これらは他のユーザーによってテストおよび検証されています。
サーバー全体
ユーザーオプション サーバー構成設定を、現在ビット単位のOR
edである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
_
データベースレベル
これは 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;
_
あまり良くないニュースは、私がこのトピックについて多くの検索を行ったことです。長年にわたって、他の多くの人がこのトピックについて多くの検索を行っており、動作を構成する方法がないことを発見しただけです。/SqlClient
。一部のMSDNドキュメントでは、ConnectionStringを介して実行できることを示唆していますが、これらの設定を変更できるキーワードはありません。別のドキュメントでは、クライアントネットワーク構成/構成マネージャーを介して変更できることを示唆していますが、それも不可能のようです。したがって、残念ながら、手動で_SET ARITHABORT ON;
_を実行する必要があります。考慮すべきいくつかの方法を次に示します。
[〜#〜] if [〜#〜]Entity Framework 6(またはそれ以降)を使用している場合は、次のいずれかを試すことができます。
Database.ExecuteSqlCommand を使用します:context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
理想的には、これはDBの接続を開いた後に1回実行され、クエリごとではありません。
インターセプター を作成します。
これにより、SQLを実行する前に変更できます。その場合は、単にプレフィックスとして_SET ARITHABORT ON;
_を付けることができます。ここでの欠点は、ローカル変数を保存して実行されたかどうかの状態をキャプチャして毎回テストする場合を除いて、クエリごとになることです(実際にはそれほど余分な作業ではありませんが、ExecuteSqlCommand
はおそらく簡単です)。
これらのどちらでも、既存のコードを変更することなく、1つの場所でこれを処理できます。
[〜#〜] else [〜#〜]、これを行うラッパーメソッドを作成すると、次のようになります。
_public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
_
次に、現在の_Reader = _Command.ExecuteReader();
参照を_Reader = ExecuteReaderWithSetting(_Command);
に変更します。
これを行うと、設定を単一の場所で処理できるようになりますが、ほとんどの場合、検索と置換を介して実行できる最小限の単純なコード変更のみが必要です。
さらに良い(Elseパート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のいずれかを拡張するクラスを作成することにより、より多くのOOスタイルで実装できます。
またはより良い(Elseパート3)、接続状態変更のイベントハンドラーを作成し、次のように、接続が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;
_を追加します。Sankar's solution を除いて、すべての接続に対してサーバーレベルで算術アボート設定を設定すると機能します。
EXEC sys.sp_configure N'user options', N'64'
GO
RECONFIGURE WITH OVERRIDE
GO
SQL 2014以降は、すべての接続で オンにすることをお勧めします です。
ログオンセッションでは、常にARITHABORTをONに設定する必要があります。 ARITHABORTをOFFに設定すると、クエリの最適化に悪影響を及ぼし、パフォーマンスの問題を引き起こす可能性があります。
したがって、これは理想的なソリューションのようです。
オプション1が実行可能ではなく、ほとんどのSQL呼び出しにストアード・プロシージャーを使用している場合(そうする必要があります ストアード・プロシージャーvs.インラインSQL を参照)、関連する各ストアード・プロシージャーでオプションを有効にするだけです。
CREATE PROCEDURE ...
AS
BEGIN
SET ARITHABORT ON
SELECT ...
END
GO
私はここでの最良のrealソリューションはコードを単に編集することだと信じています。それは間違っており、他の修正は単なる回避策です。
私はここの専門家ではありませんが、以下のようなことを試すことができます。
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();
SqlClientにARITHABORTを常にオンに設定させる設定はありません。説明のとおり、これを設定する必要があります。
おもしろいことに SET ARITHABORTに関するMicrosoftのドキュメント :-
ログオンセッションでは、常にARITHABORTをONに設定する必要があります。 ARITHABORTをOFFに設定すると、クエリの最適化に悪影響を及ぼし、パフォーマンスの問題を引き起こす可能性があります。
そして、.Net接続はこれをデフォルトでオフに設定するようにハードコードされていますか?
別の点として、この設定でパフォーマンスの問題を診断するときは、非常に注意する必要があります。設定オプションが異なると、同じクエリのクエリプランも異なります。 .Netコードでパフォーマンスの問題(SET ARITHABORT OFF)が発生する可能性がありますが、SSMSで同じTSQLクエリを実行すると(デフォルトではSET ARITHABORT ON)、問題ない可能性があります。これは、.Netクエリプランが再利用されず、新しいプランが生成されるためです。これにより、たとえば、パラメータスニッフィングの問題が排除され、パフォーマンスが大幅に向上する可能性があります。
私の場合、誰かを時間を節約する場合(Entity Framework Core 2.0.3、ASP.Net Core API、SQL Server 2008 R2):
user_options
を設定することも受け入れられませんでした(機能します-私はテストしました)、他のアプリケーションに影響を与えるリスクはありませんでした。先頭にSET ARITHABORT ON;
を付けたEF Coreからのアドホッククエリは機能しません。
最後に、私にとってうまくいった解決策は、次のように、セミコロンで区切られたSET
の前にEXEC
オプションを付けて、生のクエリとして呼び出されるストアドプロシージャを結合することです。
// C# EF Core
int result = _context.Database.ExecuteSqlCommand($@"
SET ARITHABORT ON;
EXEC MyUpdateTableStoredProc
@Param1 = {value1}
");
EF6の Solomon Rutzy answer に基づいて構築:
using System.Data;
using System.Data.Common;
namespace project.Data.Models
{
abstract class ProjectDBContextBase: DbContext
{
internal ProjectDBContextBase(string nameOrConnectionString) : base(nameOrConnectionString)
{
this.Database.Connection.StateChange += new StateChangeEventHandler(OnStateChange);
}
protected static void OnStateChange(object sender, StateChangeEventArgs args)
{
if (args.OriginalState == ConnectionState.Closed
&& args.CurrentState == ConnectionState.Open)
{
using (DbCommand _Command = ((DbConnection)sender).CreateCommand())
{
_Command.CommandType = CommandType.Text;
_Command.CommandText = "SET ARITHABORT ON;";
_Command.ExecuteNonQuery();
}
}
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
...
これはSystem.Data.Common
の代わりにDbCommand
の代わりにSqlCommand
を、DbConnection
の代わりにSqlConnection
を使用します。
SQLプロファイラートレースが確認、SET ARITHABORT ON
は、接続が開いたときに、トランザクションで他のコマンドが実行される前に送信されます。