Approche apparemment préférée
J'avais l'impression que les éléments suivants avaient déjà été testés par d'autres, en particulier sur la base de certains commentaires. Mais mes tests montrent que ces deux méthodes fonctionnent effectivement au niveau de la base de données, même lors de la connexion via .NET SqlClient
. Ceux-ci ont été testés et vérifiés par d'autres.
À l'échelle du serveur
Vous pouvez définir le paramètre de configuration du serveur d' options utilisateur pour qu'il soit ce qu'il est actuellement en bits OR
avec 64 (la valeur pour ARITHABORT
). Si vous n'utilisez pas OR ( |
) au niveau du bit mais effectuez plutôt une affectation directe ( =
), vous supprimerez toutes les autres options existantes déjà activées.
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
Au niveau de la base de données
Cela peut être défini par base de données via 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;
Approches alternatives
La moins bonne nouvelle est que j'ai fait beaucoup de recherches sur ce sujet, pour constater qu'au fil des ans, beaucoup d'autres ont fait beaucoup de recherches sur ce sujet, et il n'y a aucun moyen de configurer le comportement de SqlClient
. Certaines documentations MSDN impliquent que cela peut être fait via une ConnectionString, mais il n'y a aucun mot-clé qui permettrait de modifier ces paramètres. Un autre document implique qu'il peut être modifié via Client Network Configuration / Configuration Manager, mais cela ne semble pas non plus possible. Par conséquent, et plutôt malheureusement, vous devrez exécuter SET ARITHABORT ON;
manuellement. Voici quelques façons de considérer:
SI vous utilisez Entity Framework 6 (ou plus récent), vous pouvez essayer soit:
Utilisez Database.ExecuteSqlCommand : context.Database.ExecuteSqlCommand("SET ARITHABORT ON;");
Idéalement, cela serait exécuté une fois, après l'ouverture de la connexion DB, et non pour chaque requête.
Créez un intercepteur via:
Cela vous permettra de modifier le SQL avant qu'il ne soit exécuté, auquel cas vous pouvez simplement le préfixe avec: SET ARITHABORT ON;
. L'inconvénient est que ce sera pour chaque requête, à moins que vous stockez une variable locale pour capturer l'état de savoir si oui ou non il a été exécuté et test pour que chaque fois ( ce qui est vraiment pas que beaucoup de travail supplémentaire, mais en utilisant ExecuteSqlCommand
est probablement plus facile).
L'un ou l'autre vous permettra de gérer cela en un seul endroit sans modifier le code existant.
Sinon , vous pouvez créer une méthode wrapper qui fait cela, semblable à:
public static SqlDataReader ExecuteReaderWithSetting(SqlCommand CommandToExec)
{
CommandToExec.CommandText = "SET ARITHABORT ON;\n" + CommandToExec.CommandText;
return CommandToExec.ExecuteReader();
}
puis il suffit de changer les _Reader = _Command.ExecuteReader();
références actuelles pour être_Reader = ExecuteReaderWithSetting(_Command);
.
Cela permet également de gérer le paramètre dans un seul emplacement tout en ne nécessitant que des modifications de code minimales et simplistes qui peuvent être principalement effectuées via Find & Replace.
Mieux encore ( Else Part 2), car il s'agit d'un paramètre de niveau de connexion, il n'a pas besoin d'être exécuté pour chaque appel SqlCommand.Execute __ (). Donc, au lieu de créer un wrapper pour ExecuteReader()
, créez un wrapper pour 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;
}
Et puis il suffit de remplacer les _Connection.Open();
références existantes pour êtreOpenAndSetArithAbort(_Connection);
.
Les deux idées ci-dessus peuvent être implémentées dans un style plus OO en créant une classe qui étend SqlCommand ou SqlConnection.
Ou mieux encore ( Else Part 3), vous pouvez créer un gestionnaire d'événements pour le Connection StateChange et lui faire définir la propriété lorsque la connexion passe de Closed
à Open
comme suit:
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();
}
}
}
Avec cela en place, il vous suffit d'ajouter les éléments suivants à chaque endroit où vous créez une SqlConnection
instance:
_Connection.StateChange += new StateChangeEventHandler(OnStateChange);
Aucune modification du code existant n'est nécessaire. Je viens d'essayer cette méthode dans une petite application console, en testant en imprimant le résultat de SELECT SESSIONPROPERTY('ARITHABORT');
. Il revient 1
, mais si je désactive le gestionnaire d'événements, il revient 0
.
Par souci d'exhaustivité, voici certaines choses qui ne fonctionnent pas (ou pas du tout aussi efficacement):
- Déclencheurs de connexion : les déclencheurs, même lorsqu'ils s'exécutent dans la même session, et même s'ils s'exécutent dans une transaction démarrée explicitement, sont toujours un sous-processus et donc leurs paramètres (
SET
commandes, tables temporaires locales, etc.) lui sont locaux et ne survivent pas la fin de ce sous-processus.
- Ajouter
SET ARITHABORT ON;
au début de chaque procédure stockée:
- cela nécessite beaucoup de travail pour les projets existants, d'autant plus que le nombre de procédures stockées augmente
- cela n'aide pas les requêtes ad hoc
SELECT DATABASEPROPERTYEX('{database_name}', 'IsArithmeticAbortEnabled');
J'observe également qu'avec le retour de 1, sys.dm_exec_sessions affiche arithabort off, bien que je ne vois aucun SET explicite dans Profiler. Pourquoi serait-ce?Option 1
Outre la solution de Sankar , la définition du paramètre d'abandon arithmétique au niveau du serveur pour toutes les connexions fonctionnera:
Depuis SQL 2014, il est recommandé d'être activé pour toutes les connexions:
Cela semble donc être la solution idéale.
Option 2
Si l'option 1 n'est pas viable et que vous utilisez des procédures stockées pour la plupart de vos appels SQL (ce que vous devriez, voir Procédures stockées vs SQL en ligne ), activez simplement l'option dans chaque procédure stockée pertinente:
Je crois que la meilleure vraie solution ici est de simplement modifier votre code, car il est incorrect et tout autre correctif n'est qu'une solution de contournement.
la source
set ArithAbort off
. J'espérais quelque chose qui pourrait être fait du côté .net / C #. J'ai mis la prime, parce que j'avais vu la recommandation.Je ne suis PAS un expert ici mais vous pouvez essayer quelque chose comme ci-dessous.
Réf: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/d9e3e8ba-4948-4419-bb6b-dd5208bd7547/
la source
Il n'y a aucun paramètre pour forcer SqlClient à toujours activer ARITHABORT, vous devez le définir comme vous le décrivez.
Fait intéressant à partir de la documentation Microsoft pour SET ARITHABORT : -
Et pourtant, la connexion .Net est codée en dur pour désactiver cela par défaut?
Autre point, vous devez être très prudent lors du diagnostic des problèmes de performances avec ce paramètre. Différentes options définies entraîneront différents plans de requête pour la même requête. Votre code .Net peut rencontrer un problème de performances (SET ARITHABORT OFF) et pourtant, lorsque vous exécutez la même requête TSQL dans SSMS (SET ARITHABORT ON par défaut), cela peut être correct. En effet, le plan de requête .Net ne sera pas réutilisé et un nouveau plan sera généré. Cela pourrait potentiellement éliminer un problème de reniflage de paramètres par exemple et donner de bien meilleures performances.
la source
ANSI_WARNINGS
dans les versions ultérieures et des choses comme les vues indexées fonctionnent bien.Si cela fait gagner du temps à quelqu'un, dans mon cas (Entity Framework Core 2.0.3, ASP.Net Core API, SQL Server 2008 R2):
user_options
était acceptable pour moi (ils fonctionnent - j'ai testé) mais je ne pouvais pas risquer d'avoir un impact sur d'autres applications.Une requête ad hoc d'EF Core, avec
SET ARITHABORT ON;
en haut, ne fonctionne PAS.Enfin, la solution qui a fonctionné pour moi était la suivante: combiner une procédure stockée, appelée en tant que requête brute avec l'
SET
option avantEXEC
séparée par un point-virgule, comme ceci:la source
S'appuyant sur la réponse de Solomon Rutzy , pour EF6:
Cela utilise
System.Data.Common
'DbCommand
au lieu deSqlCommand
etDbConnection
au lieu deSqlConnection
.Une trace du Générateur de profils SQL confirme,
SET ARITHABORT ON
est envoyée lorsque la connexion s'ouvre, avant l'exécution de toute autre commande dans la transaction.la source