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