Inspiré par cette question où les opinions divergent sur SET NOCOUNT ...
Devrions-nous utiliser SET NOCOUNT ON pour SQL Server? Si non pourquoi pas
Ce qu'il fait Edit 6, le 22 juil. 2011
Il supprime le message "xx lignes affectées" après tout DML. C'est un jeu de résultats et, une fois envoyé, le client doit le traiter. C'est minuscule, mais mesurable (voir les réponses ci-dessous)
Pour les déclencheurs, etc., le client recevra plusieurs "xx lignes affectées", ce qui provoque toutes sortes d'erreurs pour certains ORM, MS Access, JPA, etc. (voir modifications ci-dessous).
Contexte:
La meilleure pratique généralement acceptée (je pensais que jusqu’à cette question) était d’utiliser SET NOCOUNT ON
dans les déclencheurs et les procédures stockées dans SQL Server. Nous l'utilisons partout et un rapide Google indique que de nombreux MVP SQL Server acceptent également.
MSDN indique que cela peut casser un .net SQLDataAdapter .
Cela signifie pour moi que SQLDataAdapter est limité au traitement CRUD simplement parce qu'il attend que le message "n lignes affectées" corresponde. Donc, je ne peux pas utiliser:
Dans la question, marc_s (qui connaît son code SQL) dit de ne pas l'utiliser. Cela diffère de ce que je pense (et je me considère aussi quelque peu compétent chez SQL).
Il est possible que quelque chose me manque (n'hésitez pas à signaler l'évidence), mais qu'en pensez-vous?
Note: cela fait des années que j'ai vu cette erreur parce que je n'utilise pas SQLDataAdapter de nos jours.
Edits après les commentaires et les questions:
Edit: Plus de pensées ...
Nous avons plusieurs clients: un peut utiliser un C # SQLDataAdaptor, un autre peut utiliser nHibernate à partir de Java. Ceux-ci peuvent être affectés de différentes manières avec SET NOCOUNT ON
.
Si vous considérez les procédures stockées comme des méthodes, il est alors mauvais (anti-modèle) de supposer que certains traitements internes fonctionnent d'une certaine manière pour vos propres besoins.
Edit 2: un déclencheur brisant la question nHibernate , où SET NOCOUNT ON
ne peut pas être défini
(et non, ce n'est pas une copie de this )
Edit 3: Encore plus d’informations, merci à mon collègue MVP
Edit 4: 13 May 2011
Pause Linq 2 SQL aussi quand non spécifié?
Éditer 5: 14 juin 2011
Interrompt JPA, proc stocké avec les variables de table: JPA 2.0 prend-il en charge les variables de table SQL Server?
Éditer 6: 15 août 2011
La grille de données SSMS "Editer les lignes" nécessite SET NOCOUNT ON: Le déclencheur de mise à jour avec GROUP BY
Éditer 7: 07 mars 2013
Plus de détails de @RemusRusanu:
SET NOCOUNT ON fait-il vraiment une différence de performance
Ok maintenant j'ai fait mes recherches, voici le deal:
Dans le protocole TDS, SET NOCOUNT ON
enregistre uniquement 9 octets par requête , tandis que le texte "SET NOCOUNT ON" lui-même représente 14 octets. J'avais l'habitude de penser que 123 row(s) affected
était renvoyé du serveur en texte brut dans un paquet réseau séparé, mais ce n'est pas le cas. C'est en fait une petite structure appelée DONE_IN_PROC
intégrée dans la réponse. Ce n'est pas un paquet réseau séparé, donc aucun aller-retour n'est gaspillé.
Je pense que vous pouvez vous en tenir au comportement de comptage par défaut presque toujours sans vous soucier de la performance. Il existe cependant des cas où le calcul préalable du nombre de lignes aurait une incidence sur les performances, par exemple un curseur avant uniquement. Dans ce cas, NOCOUNT pourrait être une nécessité. En dehors de cela, il n'est absolument pas nécessaire de suivre la devise "utilisez NOCOUNT autant que possible".
Voici une analyse très détaillée de l’insignifiance du paramètre SET NOCOUNT
: http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/
Il m'a fallu beaucoup de travail pour trouver de vrais chiffres de référence autour de NOCOUNT, alors je me suis dit que je partagerais un bref résumé.
Lorsque SET NOCOUNT est activé, le nombre (indiquant le nombre de lignes affectées par une instruction Transact-SQL) n'est pas renvoyé. Lorsque SET NOCOUNT est désactivé, le compte est renvoyé. Il est utilisé avec n'importe quelle instruction SELECT, INSERT, UPDATE, DELETE.
Le paramètre SET NOCOUNT est défini au moment de l'exécution ou de l'exécution et non au moment de l'analyse.
SET NOCOUNT ON améliore les performances de la procédure stockée (SP).
Syntaxe: SET NOCOUNT {ON | OFF}
Exemple de SET NOCOUNT ON:
Exemple de SET NOCOUNT OFF:
Je suppose que dans une certaine mesure, il s’agit d’un problème de DBA et de développeur.
En tant que développeur principalement, je dirais de ne pas l'utiliser sauf si vous devez absolument le faire, car son utilisation peut endommager votre code ADO.NET (comme documenté par Microsoft).
Et je suppose qu'en tant que DBA, vous seriez plus du côté opposé - utilisez-le autant que possible, sauf si vous devez réellement empêcher son utilisation.
De plus, si vos développeurs utilisent jamais "RecordsAffected" renvoyé par l'appel de la méthode ExecuteNonQuery
de ADO.NET, vous aurez un problème si tout le monde utilise SET NOCOUNT ON
car dans ce cas, ExecuteNonQuery renverra toujours 0.
Voir aussi le blog post de Peter Bromberg et vérifier sa position.
Donc, il s’agit vraiment de savoir qui établit les normes :-)
Marc
Si vous dites que vous pouvez également avoir des clients différents, il y a des problèmes avec classic ADO si SET NOCOUNT n'est pas défini sur ON.
Je rencontre régulièrement: si une procédure stockée exécute un certain nombre d'instructions (et donc un certain nombre de messages "lignes xxx affectés" sont renvoyés), ADO ne semble pas gérer cela et renvoie l'erreur "Impossible de modifier la propriété ActiveConnection d'un objet Recordset ayant un objet Command comme source."
Donc, je préconise généralement de l’activer sauf s’il ya vraiment vraiment une bonne raison de ne pas le faire. vous avez peut-être trouvé la très bonne raison pour laquelle je dois aller lire plus.
Au risque de compliquer les choses, j’encourage une règle légèrement différente de celle que je vois ci-dessus:
NOCOUNT ON
en haut du processus, avant de travailler dans le processus, mais aussi toujours SET NOCOUNT OFF
avant de renvoyer les jeux d'enregistrements du processus stocké. Donc, "généralement, maintenez nocount activé, sauf si vous retournez un résultat". Je ne sais pas comment cela peut casser n'importe quel code client, cela signifie que le code client n'a jamais besoin de savoir quoi que ce soit sur les éléments internes de proc, et ce n'est pas particulièrement lourd.
En ce qui concerne les déclencheurs de rupture de NHibernate, j’ai eu cette expérience de première main. En gros, lorsque NH effectue une MISE À JOUR, il s’attend à ce qu’un certain nombre de lignes soient affectées. En ajoutant SET NOCOUNT ON aux déclencheurs, vous obtenez le nombre de lignes correspondant à l'attente de NH, résolvant ainsi le problème. Donc oui, je recommanderais certainement de l'éteindre pour les déclencheurs si vous utilisez NH.
En ce qui concerne l'utilisation dans les PS, c'est une question de préférence personnelle. J'avais toujours désactivé le comptage des lignes, mais là encore, il n'y a pas de véritable argument fort dans les deux cas.
Sur une note différente, vous devriez vraiment envisager de vous éloigner de l'architecture basée sur SP, vous n'aurez alors même pas cette question.
SET NOCOUNT ON;
Cette ligne de code est utilisée dans SQL pour ne pas renvoyer le nombre de lignes affectées lors de l'exécution de la requête. Si nous n'exigeons pas le nombre de lignes affectées, nous pouvons l'utiliser car cela contribuerait à économiser l'utilisation de la mémoire et à accélérer l'exécution de la requête.
Je voulais vérifier moi-même que 'SET NOCOUNT ON' n'enregistre ni paquet réseau ni aller-retour
J'ai utilisé un test SQLServer 2017 sur un autre hôte (j'ai utilisé une machine virtuelle)
create table ttable1 (n int);
insert into ttable1 values (1),(2),(3),(4),(5),(6),(7)
go
create procedure procNoCount
as
begin
set nocount on
update ttable1 set n=10-n
end
create procedure procNormal
as
begin
update ttable1 set n=10-n
end
Ensuite, j'ai tracé les paquets sur le port 1433 à l'aide de l'outil 'Wireshark': bouton «capture filter» -> 'port 1433'
exec procNoCount
c'est le paquet de réponse:
0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00
0010 00 42 d0 ce 40 00 40 06 84 0d c0 a8 32 88 c0 a8
0020 32 01 05 99 fe a5 91 49 e5 9c be fb 85 01 50 18
0030 02 b4 e6 0e 00 00 04 01 00 1a 00 35 01 00 79 00
0040 00 00 00 fe 00 00 e0 00 00 00 00 00 00 00 00 00
exec procNormal
c'est le paquet de réponse:
0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00
0010 00 4f d0 ea 40 00 40 06 83 e4 c0 a8 32 88 c0 a8
0020 32 01 05 99 fe a5 91 49 e8 b1 be fb 8a 35 50 18
0030 03 02 e6 1b 00 00 04 01 00 27 00 35 01 00 ff 11
0040 00 c5 00 07 00 00 00 00 00 00 00 79 00 00 00 00
0050 fe 00 00 e0 00 00 00 00 00 00 00 00 00
Sur la ligne 40, je vois «07», qui correspond au nombre de «lignes affectées» ... .. Il est inclus dans le paquet de réponse. Pas de paquet supplémentaire.
Il contient cependant 13 octets supplémentaires qui pourraient être sauvegardés, mais ne vaut probablement pas plus la peine que de réduire les noms de colonne (par exemple, "ManagingDepartment" en "MD")
Donc, je ne vois aucune raison de l'utiliser pour la performance
MAIS Comme d’autres l'ont mentionné, cela peut endommager ADO.NET Je suis également tombé sur un problème lié à l'utilisation de python: MSSQL2008 - Pyodbc - Une requête SQL antérieure n'était pas une requête
Alors probablement encore une bonne habitude ...
SET NOCOUNT ON; Le code ci-dessus arrête le message généré par le moteur de serveur SQL dans la fenêtre de résultat avant la commande DML/DDL.
Pourquoi nous le faisons? Comme le moteur de serveur SQL utilise des ressources pour obtenir l’état et générer le message, il est considéré comme une surcharge du moteur de serveur SQL.
Je ne sais pas comment tester SET NOCOUNT ON entre le client et SQL. J'ai donc testé un comportement similaire pour une autre commande SET "SET TRANSACTION ISOLATION LEVEL READ UNCIMMITTED".
J'ai envoyé une commande de ma connexion en modifiant le comportement par défaut de SQL (READ COMMITTED), qui a été modifié pour les commandes suivantes . Lorsque j'ai modifié le niveau ISOLATION dans une procédure stockée, le comportement de la connexion n'a pas changé la prochaine commande.
Conclusion actuelle,
Je pense que cela est pertinent pour d'autres commandes SET telles que "SET NOCOUNT ON"
Je sais que c'est une vieille question. mais juste pour la mise à jour.
Le meilleur moyen d’utiliser «SET NOCOUNT ON» consiste à l’afficher comme première instruction dans votre SP et à le désactiver à nouveau juste avant la dernière instruction SELECT.
Un endroit que SET NOCOUNT ON
peut vraiment aider est celui où vous posez des requêtes dans une boucle ou un curseur. Cela peut générer beaucoup de trafic réseau.
CREATE PROCEDURE NoCountOn
AS
set nocount on
DECLARE @num INT = 10000
while @num > 0
begin
update MyTable SET SomeColumn=SomeColumn
set @num = @num - 1
end
GO
CREATE PROCEDURE NoCountOff
AS
set nocount off
DECLARE @num INT = 10000
while @num > 0
begin
update MyTable SET SomeColumn=SomeColumn
set @num = @num - 1
end
GO
En activant les statistiques du client dans SSMS, une exécution de EXEC NoCountOn
et EXEC NoCountOff
montre qu'il y avait un trafic supplémentaire de 390 Ko sur celui NoCountOff:
Probablement pas idéal pour faire des requêtes dans une boucle ou un curseur, mais nous ne vivons pas dans le monde idéal non plus :)
if (ne pas définir le nombre == off)
{ alors il conservera des données sur le nombre d’enregistrements affectés afin de réduire les performances } sinon { il ne suivra pas l’enregistrement des modifications améliorera donc la performance} }
Parfois, même les choses les plus simples peuvent faire la différence. Un de ces éléments simples qui devrait faire partie de chaque procédure stockée est SET NOCOUNT ON
. Cette ligne de code, placée en haut d'une procédure stockée, désactive les messages que SQL Server renvoie au client après l'exécution de chaque instruction T-SQL. Cette opération est effectuée pour toutes les instructions SELECT
, INSERT
, UPDATE
et DELETE
. Avoir ces informations est pratique lorsque vous exécutez une instruction T-SQL dans une fenêtre de requête, mais lorsque des procédures stockées sont exécutées, il n’est pas nécessaire de renvoyer ces informations au client.
En supprimant cette surcharge supplémentaire du réseau, cela peut considérablement améliorer les performances globales de votre base de données et de votre application.
Si vous devez toujours obtenir le nombre de lignes affectées par l'instruction T-SQL en cours d'exécution, vous pouvez toujours utiliser l'option @@ROWCOUNT
. En émettant un SET NOCOUNT ON
, cette fonction (@@ROWCOUNT
) fonctionne toujours et peut toujours être utilisée dans vos procédures stockées pour identifier le nombre de lignes affectées par l'instruction.