2010-08-17 14 views
10

Je l'ai vu apparaître plusieurs endroits dans le code, jamais avec une explication, juste un commentaire cryptique au-dessus (Déclaration et exécution inclus pour une idée de contexte, il est juste une procédure standard de l'exécution d'un SqlCommand.):SqlCommand.Cancel() provoque une amélioration des performances?

//SqlCommand cmd = new SqlCommand(); 
//cmd.ExecuteReader(); 
//Read off the results 

//Cancel the command. This improves query time. 
cmd.Cancel(); 

Fondamentalement, après avoir terminé une requête, il revient en arrière et annule, en réclamant une amélioration des performances. Je suppose que vous pourriez retrouver de la mémoire quand ça se passe et libérer le XmlReader, mais il est généralement sur le point de sortir de la portée de toute façon.

Je ne l'ai jamais pris la peine avec elle avant, mais il est finalement apparu dans un code que je suis passé en revue. Est-ce que l'annulation d'une SqlCommand après l'avoir exécutée dans le code l'accélère réellement, ou est-ce juste une superstition bizarre de programmeur?

+0

Avez-vous profilé le code? Il serait intéressant de voir à quel point cela a un effet. – jloubert

+0

Il y a un casse-pointe important où l'appel Annuler fait une grande différence - voir ma réponse ci-dessous –

Répondre

13

Selon MSDN, cela est exact.

La méthode Close remplit les valeurs pour les paramètres de sortie, les valeurs de retour et RecordsAffected, ce qui augmente le temps qu'il faut pour fermer un SqlDataReader qui a été utilisé pour traiter une requête importantes ou complexes. Lorsque les valeurs de retour et le nombre de enregistrements affectés par une requête ne sont pas significative, le temps qu'il faut pour fermer le SqlDataReader peut être réduite en appelant la méthode Annuler de l'objet SqlCommand associé avant appeler le Fermer méthode.

Bizarre!

+0

Huh. Je n'ai pas pensé à regarder dans le document SqlDataReader. Bonne prise! –

+1

En regardant @ le code sous-jacent, il est clair qu'il fait beaucoup de travail sur Close, cependant, je n'imaginerais pas un seul instant que cela soit si important à la fin de la journée. –

+0

A appris quelque chose ;-) Bien que je suis d'accord, vous devriez être sérieusement goulot d'étranglement sur DB IO pour remarquer le changement. – gjvdkamp

0

Notre équipe Tech à Cinchcast a fait des analyses comparatives, et nous avons trouvé que l'ajout du cmd.Cancel() ralentit réellement vers le bas.

Nous avons un appel DALC qui obtient une liste d'épisodes pour un hôte. Nous l'avons couru 1000 fois et obtenu le temps de réponse moyen pour retourner 10 épisodes.

Donc, avec le retour de 10 spectacles Moyenne Avec Annuler: 0.069s Moyenne Sans Annuler: 0.026s

assez significativement plus lent lors de l'exécution avec le retour 10 épisode.

Alors, j'ai essayé à nouveau avec le retour de 100 épisodes pour voir si un jeu de résultats plus fait une différence.

Donc, avec le retour de 100 spectacles sur chaque appel moyen avec Annuler: 0.132s Moyenne Sans Annuler: 0.122s

Cette fois-ci la différence dans le temps était beaucoup moins. Il est encore plus rapide mais sans utiliser l'annulation pour nos cas d'utilisation habituels.

7

Appel Cancel donne potentiellement amélioration de la performance MASSIVE si votre appel à ExecuteReader renvoie un grand nombre de lignes, et vous ne lit pas toutes les lignes.Pour illustrer, supposons qu'une requête renvoie un million de lignes et ferme le lecteur après avoir lu seulement les 1000 premières lignes. Si vous ne parvenez pas à appeler Cancel avant de fermer le lecteur, la méthode Close va bloc alors qu'il en interne à travers les énumère 999000 lignes restantes

Essayez et vous verrez!

+0

On ne peut pas trop sous-estimer à quel point le "Ne pas lire toutes les lignes" est la fonction principale de cette méthode. – JJS

0

Dans votre exemple, vous ouvrez le lecteur, lisez toutes les lignes et la commande Annuler la commande, mais vous n'avez pas indiqué où le lecteur était fermé.

Assurez-vous que l'annulation a lieu avant le Dispose/Close. Par exemple, vous ne seriez pas obtenir un gain de performance dans cet exemple (code réel dans la production, malheureusement):

using (var rdr = cmd.ExecuteReader (CommandBehavior.Default)) 
{ 
    retval = DocumentDir.DBRead (rdr); 
} 

// Optimization. Allows reader to close more quickly.... NOT! 
cmd.Cancel(); // bad! 

Dommage qu'il est déjà fermé par l'utilisation de déclaration!

Voici comment il faut lire pour réaliser l'avantage potentiel:

using (var rdr = cmd.ExecuteReader (CommandBehavior.Default)) 
{ 
    retval = DocumentDir.DBRead (rdr); 

    // Optimization. Allows reader to close more quickly. 
    cmd.Cancel(); 
} 

De MSDN SqlCommand.Cancel:

Dans certains, cas rares, si vous appelez ExecuteReader puis appelez Fermer (implicitement ou explicitement) avant d'appeler Annuler, puis d'appeler Annuler, la commande d'annulation ne sera pas envoyée à SQL Server et le jeu de résultats peut continuer à diffuser après avoir appelé Fermer. Pour éviter cela, veillez à appeler Annuler avant de fermer le lecteur ou la connexion.