J'ai donc déterminé que le comportement erratique de mon serveur SQL est dû au paramètre par défaut du fournisseur de données .Net SqlClient: SET ARITHABORT OFF
. Cela dit, j'ai lu divers articles qui débattent de la meilleure façon de mettre en œuvre cela. Pour moi, je veux juste un moyen facile car SQL Server souffre et mon réglage de requête n'a pas complètement transcendé à travers l'application (et évidemment ajouter le SET
dans un sp ne fonctionne pas).
Dans le brillant Erland Sommarskog article sur le sujet, il suggère essentiellement d'adopter l'approche sûre en modifiant l'application pour émettre SET ARITHABORT ON
pour la connexion. Cependant, dans cette réponse d'un dba.stackexchange question , Solomon Rutzky propose à la fois une approche à l'échelle de l'instance et à l'échelle de la base de données.
Quelles sont les ramifications qui me manquent ici avec la définition de cette instance à l'échelle? Comme je le vois ... puisque SSMS a cet ensemble ON
par défaut, je ne vois aucun mal à définir ce ON
à l'échelle du serveur pour toutes les connexions. À la fin de la journée, j'ai juste besoin de ce serveur SQL pour fonctionner avant tout.
Il y a des défauts qui existent simplement parce que personne ne sait vraiment quel serait l'effet de les changer. Par exemple, le classement par défaut au niveau de l'instance lors de l'installation sur un système qui utilise "US English" comme langue du système d'exploitation est SQL_Latin1_General_CP1_CI_AS
. Cela n'a aucun sens puisque le SQL_*
les classements sont pour la compatibilité pré-SQL Server 2000. À partir de SQL Server 2000, vous pouvez réellement choisir un classement Windows, et donc la valeur par défaut pour les systèmes en anglais américain devrait a été remplacée par Latin1_General_CI_AS
. MAIS, je suppose que personne chez Microsoft ne sait vraiment quel sera l'impact sur tous les différents sous-systèmes potentiels et procédures stockées, etc.
Donc, je ne suis au courant d'aucun impact négatif spécifique de sa définition sur ON comme valeur par défaut de la base de données ou même à l'échelle de l'instance. En même temps, je ne l'ai pas testé. Mais même si je l'avais testé, je n'utiliserais peut-être pas les mêmes chemins de code que votre application, c'est donc quelque chose que vous devez vraiment tester dans votre environnement. Définissez-le sur ON
au niveau de l'instance dans vos environnements Dev et QA et voyez comment cela fonctionne pendant un mois ou deux. Activez-le ensuite dans Staging/UAT. Si tout se passe bien pendant plusieurs semaines, passez ce changement de configuration à Production. La clé est de donner autant de temps que possible pour tester différents chemins de code qui ne sont pas touchés quotidiennement. Certains sont frappés chaque semaine ou mois ou annuellement. Certains chemins de code ne sont atteints que par le support, ou par un rapport ad hoc ou un processus de maintenance que quelqu'un a créé il y a des années et ne vous en a jamais parlé et n'est utilisé qu'à des intervalles aléatoires (non, cela ne se produit jamais ;-).
J'ai donc fait des tests sur une instance qui a toujours le paramètre par défaut "options utilisateur" car je ne l'ai jamais changé.
Notez s'il vous plaît:
@@OPTIONS
/'user options'
est une valeur masquée par bitARITHABORT ON
J'ai testé à la fois SQLCMD (qui utilise ODBC) et LINQPad (qui utilise .NET SqlClient):
SQLCMD -W -S (local) ^
-Q"SELECT CONCAT(DB_NAME(), N': ', @@OPTIONS & 64, N' (', ses.[client_interface_name], N')') FROM sys.dm_exec_sessions ses WHERE ses.[session_id] = @@SPID;"
echo .
(le ^
est le caractère de continuation de la ligne DOS; le .
sur la dernière ligne consiste simplement à forcer la ligne supplémentaire pour faciliter le copier-coller)
Dans LINQPad:
using (SqlConnection connection =
new SqlConnection(@"Server=(local);Trusted_Connection=true;Database=tempdb;"))
{
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = @"SELECT @RetVal =
CONCAT(DB_NAME(), N': ', @@OPTIONS & 64, N' (', ses.[client_interface_name], N')')
FROM sys.dm_exec_sessions ses
WHERE ses.[session_id] = @@SPID;";
SqlParameter paramRetVal = new SqlParameter("@RetVal", SqlDbType.NVarChar, 500);
paramRetVal.Direction = ParameterDirection.Output;
command.Parameters.Add(paramRetVal);
connection.Open();
command.ExecuteNonQuery();
Console.WriteLine(paramRetVal.Value.ToString());
}
}
SQLCMD renvoie:
master: 0 (ODBC)
LINQPad renvoie:
tempdb: 0 (.Net SqlClient Data Provider)
Le T-SQL suivant active ARITHABORT
sans supprimer les autres options qui pourraient être définies et sans rien changer si ARITHABORT
est déjà défini dans la valeur masquée par bit.
DECLARE @UserOptions INT;
-- Get current bitmasked value and ensure ARITHABORT is enabled:
SELECT @UserOptions = CONVERT(INT, cnf.[value_in_use]) | 64 -- enable "ARITHABORT"
FROM sys.configurations cnf
WHERE cnf.[configuration_id] = 1534 -- user options
-- Apply new default connection options:
EXEC sys.sp_configure N'user options', @UserOptions;
RECONFIGURE;
SQLCMD renvoie:
master: 64 (ODBC)
LINQPad renvoie:
tempdb: 64 (.Net SqlClient Data Provider)
Étant donné que:
ARITHABORT OFF
ARITHABORT ON
OFF
ARITHABORT
, ils acceptent donc le paramètre par défautJe suggère de modifier les options de connexion par défaut à l'échelle de l'instance (comme indiqué ci-dessus). Ce serait moins gênant que la mise à jour de l'application. Je ne mettrais à jour que l'application si vous rencontrez un problème avec la modification du paramètre à l'échelle de l'instance.
P.S. J'ai fait un test simple en changeant tempdb
et not en changeant le paramètre à l'échelle de l'instance et cela ne semblait pas fonctionner.