Scheinbar bevorzugter Ansatz
Ich hatte den Eindruck, dass das Folgende bereits von anderen getestet wurde, insbesondere aufgrund einiger Kommentare. Meine Tests haben jedoch gezeigt, dass diese beiden Methoden tatsächlich auf DB-Ebene funktionieren, selbst wenn eine Verbindung über .NET hergestellt wird SqlClient
. Diese wurden von anderen getestet und verifiziert.
Serverweit
Sie können die Serverkonfigurationseinstellung für Benutzeroptionen so festlegen , dass sie OR
mit 64 (dem Wert für ARITHABORT
) den aktuellen Bit- Wert annimmt . Wenn Sie nicht das bitweise ODER ( |
) verwenden, sondern eine direkte Zuordnung ( =
) vornehmen, werden alle anderen bereits aktivierten Optionen gelöscht.
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
Datenbankebene
Dies kann pro Datenbank über ALTER DATABASE SET eingestellt werden :
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;
Alternative Ansätze
Die nicht so gute Nachricht ist, dass ich viel nach diesem Thema gesucht habe, nur um festzustellen, dass im Laufe der Jahre viele andere viel nach diesem Thema gesucht haben und es keine Möglichkeit gibt, das Verhalten zu konfigurieren von SqlClient
. Einige MSDN-Dokumentationen implizieren, dass dies über einen ConnectionString erfolgen kann, es gibt jedoch keine Schlüsselwörter, mit denen diese Einstellungen geändert werden könnten. Ein anderes Dokument impliziert, dass es über Client-Netzwerkkonfiguration / Configuration Manager geändert werden kann, aber dies scheint auch nicht möglich zu sein. Daher und leider müssen Sie SET ARITHABORT ON;
manuell ausführen . Hier sind einige Möglichkeiten zu berücksichtigen:
Wenn Sie Entity Framework 6 (oder neuer) verwenden, können Sie Folgendes versuchen:
Use Database.ExecuteSqlCommand : Im context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
Idealfall wird dies einmal nach dem Öffnen der DB-Verbindung ausgeführt und nicht für jede Abfrage.
Erstellen Sie einen Abfangjäger über:
Dies ermöglicht Ihnen , die SQL zu ändern , bevor es ausgeführt wird, in welchem Fall Sie einfach mit ihm Präfix kann: SET ARITHABORT ON;
. Der Nachteil hierbei ist, dass dies bei jeder Abfrage der Fall ist, es sei denn, Sie speichern eine lokale Variable, um den Status zu erfassen, ob sie ausgeführt wurde, und testen sie jedes Mal (was wirklich nicht so viel zusätzliche Arbeit ist, aber mit ExecuteSqlCommand
ist wahrscheinlich einfacher).
In beiden Fällen können Sie dies an einer Stelle erledigen, ohne den vorhandenen Code zu ändern.
Anderenfalls könnten Sie eine Wrapper-Methode erstellen, die dies ausführt, ähnlich wie:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
und dann einfach die aktuellen _Reader = _Command.ExecuteReader();
referenzen ändern _Reader = ExecuteReaderWithSetting(_Command);
.
Auf diese Weise kann die Einstellung auch an einem einzigen Ort vorgenommen werden, während nur minimale und vereinfachte Codeänderungen erforderlich sind, die meist über Suchen und Ersetzen vorgenommen werden können.
Besser noch ( sonst Teil 2), da dies eine Einstellung auf Verbindungsebene ist, muss sie nicht bei jedem Aufruf von SqlCommand.Execute __ () ausgeführt werden. Anstatt einen Wrapper für zu ExecuteReader()
erstellen, erstellen Sie einen Wrapper für 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;
}
Und dann einfach die vorhandenen _Connection.Open();
Referenzen ersetzen lassen OpenAndSetArithAbort(_Connection);
.
Beide oben genannten Ideen können im OO-Stil implementiert werden, indem eine Klasse erstellt wird, die entweder SqlCommand oder SqlConnection erweitert.
Oder noch besser ( Else Teil 3), können Sie einen Ereignishandler für das Connection Statechange erstellen und haben sie die Eigenschaft , wenn die Verbindung ändert sich von Closed
zu Open
wie folgt:
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();
}
}
}
Damit müssen Sie nur an jeder Stelle, an der Sie eine SqlConnection
Instanz erstellen, Folgendes hinzufügen :
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Es sind keine Änderungen am vorhandenen Code erforderlich. Ich habe diese Methode gerade in einer kleinen Konsolen-App ausprobiert, indem ich das Ergebnis von teste SELECT SESSIONPROPERTY('ARITHABORT');
. Es kehrt zurück 1
, aber wenn ich den Event Handler deaktiviere, kehrt es zurück 0
.
Der Vollständigkeit halber sind hier einige Dinge, die nicht (entweder überhaupt oder nicht so effektiv) funktionieren:
- Anmelde-Trigger : Trigger sind selbst dann, wenn sie in derselben Sitzung ausgeführt werden und wenn sie innerhalb einer explizit gestarteten Transaktion ausgeführt werden, immer noch ein Unterprozess. Daher sind die Einstellungen (
SET
Befehle, lokale temporäre Tabellen usw.) lokal und überleben nicht das Ende dieses Unterprozesses.
- Hinzufügen
SET ARITHABORT ON;
am Anfang jeder gespeicherten Prozedur:
- Dies erfordert eine Menge Arbeit für vorhandene Projekte, insbesondere wenn die Anzahl der gespeicherten Prozeduren zunimmt
- Dies hilft nicht bei Ad-hoc-Anfragen