web-dev-qa-db-fra.com

SET NOCOUNT ON utilisation

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:

  • SI EXISTE pour éviter les doublons (aucune ligne ne concerne le message) Remarque: à utiliser avec prudence
  • WHERE NOT EXISTS (moins de lignes que prévu
  • Filtrez les mises à jour triviales (par exemple, aucune donnée ne change réellement)
  • N'importe quel accès à la table avant (comme la journalisation)
  • Masquer la complexité ou la dénormlisation
  • etc

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

289
gbn

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/

195
Sedat Kapanoglu

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é.

  • Si votre procédure stockée utilise un curseur pour effectuer de nombreuses opérations très rapides sans résultats renvoyés, la désactivation de NOCOUNT peut prendre environ 10 fois plus longtemps que son activation. 1 C'est le pire des cas.
  • Si votre procédure stockée n'effectue qu'une seule opération rapide sans résultats renvoyés, la définition de NOCOUNT ON produira une augmentation de performances d'environ 3%. 2 Cela serait cohérent avec une procédure d'insertion ou de mise à jour typique.
  • Si votre procédure stockée renvoie des résultats (c’est-à-dire que vous sélectionnez quelque chose), la différence de performances diminuera proportionnellement à la taille de l’ensemble de résultats.
79
StriplingWarrior
  • 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:

enter image description here

Exemple de SET NOCOUNT OFF:

enter image description here

57
Bhaumik Patel

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

30
marc_s

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.

11
Chris J

Au risque de compliquer les choses, j’encourage une règle légèrement différente de celle que je vois ci-dessus: 

  • Définissez toujours 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.

9
Tao

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.

5
zvolkov
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.

1
user1509

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 ...

1
phil_w

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.

1
Subhransu Panda

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,

  1. La modification des paramètres dans la procédure stockée ne modifie pas les paramètres par défaut de la connexion.
  2. La modification d'un paramètre en envoyant des commandes à l'aide de ADOCOnnection modifie le comportement par défaut.

Je pense que cela est pertinent pour d'autres commandes SET telles que "SET NOCOUNT ON"

0
Rabia Mansour

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.

0
KRules

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:

 client statistics

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 :)

0
bcoughlan

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} }

0
Shubham Sharma

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.

0
Vinayak Savale