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
SELECT DATABASEPROPERTYEX('{database_name}', 'IsArithmeticAbortEnabled');
Rückgabe von 1 sys.dm_exec_sessions Arithabort ausschaltet, obwohl ich in Profiler keine expliziten SETs sehe. Warum sollte das so sein?Option 1
Abgesehen von der Lösung von Sankar funktioniert das Festlegen der Einstellung für den arithmetischen Abbruch auf Serverebene für alle Verbindungen:
Ab SQL 2014 wird empfohlen, für alle Verbindungen aktiviert zu sein :
Dies scheint also die ideale Lösung zu sein.
Option 2
Wenn Option 1 nicht durchführbar ist und Sie für die meisten Ihrer SQL-Aufrufe gespeicherte Prozeduren verwenden (siehe Gespeicherte Prozeduren vs. Inline-SQL ), aktivieren Sie einfach die Option in jeder relevanten gespeicherten Prozedur:
Ich glaube, die beste echte Lösung besteht darin, Ihren Code einfach zu bearbeiten, da dies falsch ist und jede andere Korrektur lediglich eine Problemumgehung darstellt.
quelle
set ArithAbort off
. Ich habe auf etwas gehofft, das auf der .net / C # -Seite getan werden kann. Ich habe das Kopfgeld ausgesetzt, weil ich die Empfehlung gesehen hatte.Ich bin hier kein Experte, aber Sie können etwas wie unten versuchen.
Ref: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/d9e3e8ba-4948-4419-bb6b-dd5208bd7547/
quelle
Es gibt keine Einstellung, die SqlClient zwingt, ARITHABORT immer zu aktivieren. Sie müssen dies wie beschrieben einstellen.
Interessanterweise aus der Microsoft-Dokumentation zu SET ARITHABORT : -
Und doch ist die .Net-Verbindung fest programmiert, um dies standardmäßig zu aktivieren?
Außerdem müssen Sie bei der Diagnose von Leistungsproblemen mit dieser Einstellung sehr vorsichtig sein. Unterschiedliche Set-Optionen führen zu unterschiedlichen Abfrageplänen für dieselbe Abfrage. Bei Ihrem .Net-Code kann ein Leistungsproblem auftreten (SET ARITHABORT OFF). Wenn Sie jedoch dieselbe TSQL-Abfrage in SSMS ausführen (SET ARITHABORT ON standardmäßig), ist dies möglicherweise in Ordnung. Dies liegt daran, dass der .Net-Abfrageplan nicht wiederverwendet und ein neuer Plan generiert wird. Dies könnte beispielsweise ein Parameter-Sniffing-Problem beseitigen und die Leistung erheblich verbessern.
quelle
ANSI_WARNINGS
in späteren Versionen von on impliziert, und Dinge wie indizierte Ansichten funktionieren einwandfrei.Wenn es jemandem Zeit spart, in meinem Fall (Entity Framework Core 2.0.3, ASP.Net Core API, SQL Server 2008 R2):
user_options
Datenbank war für mich akzeptabel (sie funktionieren - ich habe sie getestet), aber ich konnte nicht riskieren, andere Anwendungen zu beeinträchtigen.Eine Ad-hoc-Abfrage von EF Core mit
SET ARITHABORT ON;
oben funktioniert NICHT.Die Lösung, die für mich funktioniert hat, war: Eine gespeicherte Prozedur, die als unformatierte Abfrage aufgerufen wird, mit der
SET
OptionEXEC
kombinieren, bevor sie durch ein Semikolon getrennt wird:quelle
Aufbauend auf der Antwort von Solomon Rutzy für EF6:
Dies verwendet
System.Data.Common
'sDbCommand
anstelle vonSqlCommand
undDbConnection
anstelle vonSqlConnection
.Eine SQL Profiler-Ablaufverfolgung
SET ARITHABORT ON
wird beim Öffnen der Verbindung gesendet, bevor andere Befehle in der Transaktion ausgeführt werden.quelle