Utilisez l'invite SQL pour trouver les problèmes de code SET NOCOUNT

SQL Prompt est un outil pratique d'invite de syntaxe SQL. SQL Prompt recherche automatiquement en fonction du nom de l'objet, de la grammaire et des fragments de code de la base de données, et fournit aux utilisateurs la sélection de code appropriée. Les paramètres de script automatiques rendent le code simple et facile à lire - particulièrement utile lorsque les développeurs ne sont pas familiarisés avec les scripts. SQL Prompt est installé et prêt à être utilisé, ce qui peut considérablement améliorer l'efficacité du codage. En outre, les utilisateurs peuvent le personnaliser au besoin pour le faire fonctionner de la manière attendue.

SQL Prompt implémente deux règles d'analyse de code statique pour vérifier si le code peut abuser de la commande SET NOCOUNT:

  • PE008 - SET NOCOUNT OFF utilisation
  • PE009-SET NOCOUNT ONDML pas avant

Chaque fois qu'une requête est exécutée, un court message sera renvoyé au client, qui contient le nombre de lignes affectées par l'instruction T-SQL. Lorsque vous utilisez SET NOCOUNT ON, ce message ne sera pas envoyé. Cela peut améliorer les performances en réduisant légèrement le trafic réseau. Il est préférable d'utiliser SET NOCOUNT ON dans les déclencheurs et les procédures stockées SQL Server, sauf si une ou plusieurs applications utilisant des procédures stockées exigent qu'il soit défini sur OFF car ils lisent la valeur du message. SET NOCOUNT ON n'affectera pas les résultats renvoyés. DONE_IN_PROC pour chaque instruction exécutée, il ne supprime que les paquets de messages redondants, sinon il renverra ces paquets de messages au client sous forme de petits paquets de messages (neuf octets). La logique basée sur le serveur et les valeurs telles que @@ ROWCOUNT ne sont pas affectées.
Par défaut, SET NOCOUNT est défini sur OFF au niveau de l'instance SQL Server, ce qui signifie que DONE_IN_PROC enverra un message au client pour chaque instruction de la procédure stockée. Lorsque vous utilisez les utilitaires fournis pour exécuter des requêtes avec Microsoft SQL Server, le message «La ligne NN est affectée» sera par défaut à la fin des instructions Transact-SQL telles que SELECT, INSERT, UPDATE et DELETE.

Microsoft recommande d'utiliser de manière sélective SET NOCOUNT ON au niveau de la session pour empêcher l'envoi de ces messages: «Pour les procédures stockées qui contiennent plusieurs instructions qui ne renvoient pas de grandes quantités de données réelles, l'élimination de ces messages peut considérablement améliorer les performances en raison de la grande quantité de le trafic réseau. diminue beaucoup ".

En général, la meilleure approche consiste à empêcher l'envoi de messages de nombre de lignes (sauf s'ils doivent être envoyés), mais la partie la plus délicate est de s'adapter aux applications plus anciennes qui utilisent et abusent souvent de ces messages. De plus, pour le traitement asynchrone du processus par la couche intermédiaire d'une application de base de données (telle que ORM), l'envoi de ces messages peut parfois devenir un problème. Par rapport au résultat de la procédure stockée, le message de comptage de lignes est transmis au client beaucoup plus lentement, ce qui peut bloquer le thread.

Qu'est-ce qu'un message?

La connexion avec la base de données transmet les données et les messages séparément. Dans Management Studio (SSMS), lorsque les résultats de la requête sont présentés sous forme de grille, ils sont représentés par des volets séparés dans la fenêtre de requête. Lorsque la connexion sqlClient est établie, le gestionnaire InfoMessage peut lire le flux de messages. Afin de permettre au client de lire et de traiter les avertissements ou les messages envoyés par le serveur, le client peut écouter ces messages via le délégué SqlInfoMessageEventHandler qui peut répondre à ces événements.

Dans cet article, nous nous concentrons uniquement sur un type de message. Lignes. Cependant, SQL Server peut également envoyer des messages en réponse à des commandes spécifiques. Même RAISERROR (gravité 10 ou inférieure) et le trio d'instructions PRINT et d'instructions SET STATISTICS (SET STATISTICS IO ON, SET STATISTICS TIME ON, SET STATISTICS XML ON). Mon article "Tests SQL DML réguliers pour les testeurs peu enthousiastes" illustre la valeur de l'utilisation de ce flux de messages lors de la surveillance des performances. La commande SET NOCOUNT détermine uniquement s'il faut envoyer un message de comptage de lignes.

Plusieurs applications, composants, widgets (tels que des grilles) et intergiciels (tels que ORM) utilisent des messages de nombre de lignes pour obtenir le nombre actuel de résultats de données. Même dans la même situation, il est souvent difficile de faire correspondre la requête avec le message de comptage. Session De nombreuses autres requêtes sont exécutées, ce qui peut également provoquer un blocage des threads. Il est préférable de fermer ces messages de comptage de lignes SET NOCOUNT ON dans le code de retour de la procédure ou via l'utilisation de variables de sortie et d'utiliser la valeur return count @@ ROWCOUNT. Cependant, il y a beaucoup d'anciens codes qui doivent être pris en compte.

Quelle est la portée de SET NOCOUNT?

Après avoir établi une connexion avec SQL Server et démarré une session, vous ne devez définir NOCOUNT qu'une seule fois, ce qui affectera tout ce que vous faites dans cette session. SET L'instruction que vous faites ne changera que le traitement d'informations spécifiques dans la session en cours; chaque lot que vous exécutez dans cette session héritera de ces paramètres.

Si SET exécute une instruction dans une procédure stockée ou un déclencheur, SET restaurera la valeur précédente de l'option après avoir renvoyé le contrôle de la procédure stockée ou du déclencheur. De même, si SET NOCOUNT a une instruction EXECUTE dans la chaîne SQL dynamique qui est exécutée à l'aide de sp_executesql ou, alors la valeur initiale de l'option sera restaurée une fois que SET aura exécuté la chaîne SQL dynamique. Par conséquent, il n'est pas nécessaire de définir explicitement NOCOUNT à la fin de la procédure stockée ou du déclencheur.

À l'exception des procédures, des déclencheurs et des lots exécutés dynamiquement, tous les paramètres de la session NOCOUNT resteront dans la session jusqu'à ce qu'ils soient modifiés.

Quels sont les avantages de performance de SET NOCOUNT ON?

En utilisant une procédure stockée bien conçue, vous n'obtiendrez qu'une amélioration négligeable des performances NOCOUNT en remplaçant les paramètres par défaut à l'échelle du serveur. En d'autres termes, dans des circonstances particulières, l'utilisation de SET NOCOUNT ON apportera d'énormes avantages. Tout dépend du nombre et de la fréquence des requêtes exécutées dans le processus. Par exemple, si un processus utilise des curseurs pour exécuter de nombreuses requêtes, les résultats de ces requêtes font alors partie de la requête renvoyée, ou si le processus contient de nombreuses instructions qui ne renvoient pas une grande quantité de données réelles, le processus peut être exécuté par rapport à la vitesse Dix fois NOCOUNT OFF, car le trafic réseau est considérablement réduit. Seules une ou deux requêtes sont exécutées dans le processus et le chiffre d'affaires sera inférieur à 5%.

Pourquoi ne pas simplement activer NOCOUNT au niveau de l'instance de base de données?

Les paramètres de configuration du serveur d'options utilisateur spécifient «par défaut global» pour chaque option SET, y compris NOCOUNT. Par défaut, l'instance SQL Server sera désactivée par NOCOUNT, de sorte que chaque instruction émise sur la base de données sur cette instance entraînera un message renvoyé à la fin indiquant le nombre de lignes affectées.

Vous pouvez utiliser sp_configure pour modifier le comportement au niveau de l'instance afin d'activer NOCOUNT et empêcher l'envoi de ces messages, comme indiqué dans la liste 1. Cela affectera les paramètres par défaut de toutes les sessions utilisateur démarrées une fois les paramètres définis.
EXEC sys.sp_configure 'user options', '512'; - 512 = NOCOUNT
Listing 1
Les utilisateurs peuvent remplacer les valeurs par défaut au niveau du serveur en émettant des instructions SET NOCOUNT qui n'affectent que leur session unique.

Les déclencheurs ne doivent pas envoyer de messages de nombre de lignes; il n'y a pas d'exceptions à cette règle. En fait, si la couche d'application intermédiaire attend certains messages de comptage de lignes et utilise son SET NOCOUNT OFF pour les déclencheurs, cela peut provoquer d'étranges erreurs aléatoires. Même la grille de données de SSMS peut offenser le problème de déclenchement.

Cependant, dans d'autres endroits, il existe de nombreuses exceptions. Si vous disposez d'anciens composants qui utilisent les messages de nombre de lignes renvoyés pour accéder à la base de données, le blocage de ces messages au niveau de l'instance peut entraîner des problèmes. Normalement, ces composants peuvent être facilement pris en charge en définissant correctement les procédures stockées utilisées par ces composants via NOCOUNT. Cependant, s'ils accèdent directement à la table et que vous ne pouvez pas ajouter SET NOCOUNT OFF pour ces sessions, il serait imprudent de modifier les paramètres de niveau d'instance de base de données.

De même, si un composant de l'application (tel que ORM ou LINQ) abuse de ce message pour déterminer le nombre de lignes du résultat, alors si vous désactivez le message, quelque chose de mauvais peut se produire.

Quel mal se produira si vous activez NOCOUNT?

Si vous utilisez DataAdaptor pour appeler des procédures stockées SQL Server pour modifier ou supprimer des données, veuillez ne pas utiliser SET NOCOUNT ON dans la définition de procédure stockée. Cela entraînera le retour à zéro du nombre de lignes affectées et le DataAdapter lèvera une exception DBConcurrencyException. En fait, une programmation défensive judicieuse signifiera que SET NOCOUNT OFF émettra des recommandations claires dans ces situations.

La classe sqlclient.sqlcommand peut également rencontrer des problèmes avec SET NOCOUNT ON, qui peuvent être causés par la façon dont le client utilise ODBC. Lorsque l'application appelle SQLRowCount, le message de nombre de lignes est disponible dans ODBC. Il ne s'agit pas d'informations fiables car certaines sources de données ne peuvent pas renvoyer le nombre de lignes du jeu de résultats avant que le résultat ne soit obtenu.

Même dans SQL Server, cette valeur n'est fiable que si vous NOCOUNT testez ultérieurement "l'état" après avoir lu SQLRowCount. Lorsque l'option NOCOUNT est définie sur on, SQLROWCOUNT renvoie 0, même s'il existe des résultats. Si SQLRowCount renvoie 0, l'application doit déterminer si NOCOUNT est en testant la valeur de la propriété spécifique à SQL Server. Si cette valeur est renvoyée, la valeur de SQLRowCount de 0 signifie uniquement que SQL Server n'a pas renvoyé le nombre de lignes. S'il retourne, cela signifie qu'il est fermé et que la valeur dans SQLRowCount est 0ONSQL_SOPT_SS_NOCOUNT_STATUSSQL_NC_ONSQL_NC_OFFNOCOUNT indiquant que l'instruction n'affecte aucune ligne, il n'est donc pas nécessaire de traiter le résultat.

Alors, quelles sont les recommandations des «meilleures pratiques»?

Une suggestion simple et faisable consiste à conserver l'état par défaut du niveau d'instance de base de données inchangé et à SET NOCOUNT ON pour en ajouter un au début de chaque procédure stockée, déclencheur et lot exécuté dynamiquement. Cette règle s'appliquera à tous les déclencheurs sans exception. Les procédures stockées n'auront pas non plus besoin de ces messages à moins que l'application qui tente de les utiliser pour obtenir le nombre de lignes de résultat les appelle depuis l'extérieur de la base de données. En règle générale, il est préférable d'utiliser la valeur de @@ RowCount pour envoyer le nombre à la variable de sortie, mais cela n'aide pas les composants d'application préexistants. Si vous devez vous assurer que la requête renvoie un message de nombre de lignes, vous devez le spécifier au lieu d'utiliser le paramètre actuel.

Je suppose que tu aimes

Origine blog.51cto.com/15078157/2621474
conseillé
Classement