Vous vous demandez simplement si certains d'entre vous utilisent Count(1)
trop Count(*)
et s'il y a une différence notable dans les performances ou si c'est juste une habitude héritée qui a été avancée depuis des jours passés?
La base de données spécifique est SQL Server 2005
.
sql
sql-server
performance
super9
la source
la source
COUNT(*)
vsCOUNT(1)
vsCOUNT(pk)
- quelle est la meilleure? . Il y a aussiCOUNT(*)
vsCOUNT(column-name)
- qui est plus correct? . Il pourrait bien y avoir d'autres doublons.Réponses:
Il n'y a pas de différence.
Raison:
"1" est une expression non nulle: c'est donc la même chose que
COUNT(*)
. L'optimiseur le reconnaît pour ce qu'il est: trivial.Identique à
EXISTS (SELECT * ...
ouEXISTS (SELECT 1 ...
Exemple:
Même IO, même plan, les travaux
Edit, août 2011
Question similaire sur DBA.SE .
Edit, déc.2011
COUNT(*)
est mentionné spécifiquement dans ANSI-92 (recherchez "Scalar expressions 125
")Autrement dit, la norme ANSI le reconnaît comme saignant ce que vous voulez dire.
COUNT(1)
a été optimisé par les fournisseurs de SGBDR en raison de cette superstition. Sinon, il serait évalué selon ANSIla source
Dans SQL Server, ces instructions produisent les mêmes plans.
Contrairement à l'opinion populaire, ils le font aussi dans Oracle.
SYS_GUID()
dans Oracle est une fonction assez intensive en calcul.Dans ma base de données de test,
t_even
est une table avec des1,000,000
lignesCette requête:
s'exécute pendant
48
quelques secondes, car la fonction doit évaluer chaqueSYS_GUID()
retour pour s'assurer qu'il ne s'agit pas d'unNULL
.Cependant, cette requête:
ne fonctionne que pendant
2
quelques secondes, car il n'essaie même pas d'évaluerSYS_GUID()
(bien qu'il*
soit un argument pourCOUNT(*)
)la source
SYS_GUID()
au moins (je veux dire exactement) une fois pour que la sous-requête renvoie le résultat, non?COUNT(*)
dépend-on des valeurs deSYS_GUID
?COUNT(*)
à exécuter, il a besoin d'une table, donc la sous-requête devrait agir comme telle. Sinon, je ne vois pas de moyenCOUNT(*)
de retourner une valeur significativemap
méthode, voyez-vous comment ces deux expressions:t_even.map(() => sys_guid()).length
ett_even.length
renverraient toujours la même valeur? L'optimiseur d'Oracle est suffisamment intelligent pour le voir et optimiser lamap
pièce.length
ne dépend pas tout à fait ce que la collection se compose, juste sur le nombre de ses éléments. Si ce numéro est stocké dans les métadonnées de la collection (ce n'est pas le cas pour Oracle ou la plupart des autres SGBDR modernes mais c'est le cas pour l'ancien moteur de stockage de MySQL, MyISAM), ilCOUNT(*)
suffirait alors de prendre la valeur des métadonnées.De toute évidence,
COUNT(*)
etCOUNT(1)
sera toujours le même résultat. Par conséquent, si l'un était plus lent que l'autre, cela serait effectivement dû à un bug d'optimisation. Étant donné que les deux formulaires sont utilisés très fréquemment dans les requêtes, cela n'aurait aucun sens pour un SGBD de permettre à un tel bogue de rester non corrigé. Par conséquent, vous constaterez que les performances des deux formulaires sont (probablement) identiques dans tous les principaux SGBD SQL.la source
Je travaille sur l'équipe SQL Server et je peux, espérons-le, clarifier quelques points dans ce fil (je ne l'avais pas vu auparavant, donc je suis désolé que l'équipe d'ingénierie ne l'ait pas fait auparavant).
Tout d' abord, il n'y a pas de différence sémantique entre en
select count(1) from table
fonctionselect count(*) from table
. Ils retournent les mêmes résultats dans tous les cas (et c'est un bug sinon). Comme indiqué dans les autres réponses,select count(column) from table
est sémantiquement différent et ne renvoie pas toujours les mêmes résultats quecount(*)
.Deuxièmement, en ce qui concerne les performances, deux aspects importent dans SQL Server (et SQL Azure): le travail au moment de la compilation et le travail au moment de l'exécution. Le travail de temps de compilation est une quantité de travail supplémentaire insignifiante dans l'implémentation actuelle. Dans certains cas, il y a une extension de * à toutes les colonnes suivie d'une réduction à 1 colonne en raison de la façon dont certaines des opérations internes fonctionnent dans la liaison et l'optimisation. Je doute que cela apparaisse dans n'importe quel test mesurable et se perdrait probablement dans le bruit de toutes les autres choses qui se produisent sous les couvertures (telles que les statistiques automatiques, les sessions xevent, les frais généraux du magasin de requêtes, les déclencheurs, etc.). Il s'agit peut-être de quelques milliers d'instructions CPU supplémentaires. Donc, count (1) fait un tout petit peu moins de travail pendant la compilation (ce qui se produit généralement une fois et le plan est mis en cache sur plusieurs exécutions ultérieures). Pour le temps d'exécution, en supposant que les plans sont les mêmes, il ne devrait pas y avoir de différence mesurable. (L'un des exemples précédents montre une différence - il est probablement dû à d'autres facteurs sur la machine si le plan est le même).
Quant à savoir comment le plan peut être différent. Il est extrêmement peu probable que cela se produise, mais cela est potentiellement possible dans l'architecture de l'optimiseur actuel. L'optimiseur de SQL Server fonctionne comme un programme de recherche (pensez: programme informatique jouant aux échecs en cherchant à travers différentes alternatives pour différentes parties de la requête et en évaluant les alternatives pour trouver le plan le moins cher dans un délai raisonnable). Cette recherche a quelques limites sur la façon dont elle fonctionne pour que la compilation des requêtes se termine dans un délai raisonnable. Pour les requêtes au-delà des plus triviales, il existe des phases de la recherche et elles traitent des tranches de requêtes basées sur le coût que l'optimiseur pense que la requête doit potentiellement exécuter. Il y a 3 phases de recherche principales, et chaque phase peut exécuter des heuristiques plus agressives (coûteuses) en essayant de trouver un plan moins cher que n'importe quelle solution antérieure. En fin de compte, il y a un processus de décision à la fin de chaque phase qui essaie de déterminer s'il doit retourner le plan qu'il a trouvé jusqu'à présent ou s'il doit continuer à chercher. Ce processus utilise le temps total pris jusqu'à présent par rapport au coût estimé du meilleur plan trouvé jusqu'à présent. Ainsi, sur différentes machines avec différentes vitesses de CPU, il est possible (bien que rare) d'obtenir des plans différents en raison du dépassement du délai dans une phase antérieure avec un plan par rapport à la poursuite de la phase de recherche suivante. Il existe également quelques scénarios similaires liés à la temporisation de la dernière phase et potentiellement à un manque de mémoire sur des requêtes très, très coûteuses qui consomment toute la mémoire de la machine (ce qui n'est généralement pas un problème sur 64 bits mais c'était une préoccupation plus importante sur des serveurs 32 bits). En fin de compte, si vous obtenez un plan différent, les performances au moment de l'exécution seraient différentes. Je ne '
Net-net: veuillez utiliser celui des deux que vous voulez car rien de tout cela n'a d'importance sous aucune forme pratique. (Honnêtement, il existe des facteurs bien plus importants qui affectent les performances de SQL au-delà de cette rubrique).
J'espère que ça aide. J'ai écrit un chapitre de livre sur le fonctionnement de l'optimiseur, mais je ne sais pas s'il est approprié de le poster ici (car j'en tire encore de minuscules redevances, je crois). Donc, au lieu de publier ce que je vais publier un lien vers une conférence que j'ai donnée à SQLBits au Royaume-Uni sur le fonctionnement de l'optimiseur à un niveau élevé afin que vous puissiez voir les différentes phases principales de la recherche un peu plus en détail si vous le souhaitez pour en savoir plus. Voici le lien vidéo: https://sqlbits.com/Sessions/Event6/inside_the_sql_server_query_optimizer
la source
1
subit également la même expansion. Je base cela sur les tests de performance ici stackoverflow.com/questions/1597442/… voir également l'exemple dans cette réponse d'une requête utilisant l'1
échec de manière inattendue lorsque les autorisations au niveau des colonnes sont en jeuDans la norme SQL-92,
COUNT(*)
signifie spécifiquement "la cardinalité de l'expression de table" (pourrait être une table de base, `VIEW, table dérivée, CTE, etc.).Je suppose que l'idée était
COUNT(*)
facile à analyser. L'utilisation d'une autre expression nécessite que l'analyseur s'assure qu'il ne référence aucune colonne (COUNT('a')
oùa
est un littéral etCOUNT(a)
oùa
est une colonne peut donner des résultats différents).Dans le même ordre d'idées,
COUNT(*)
peut être facilement sélectionné par un codeur humain familiarisé avec les normes SQL, une compétence utile lorsque vous travaillez avec plusieurs offres SQL d'un fournisseur.De plus, dans le cas particulier
SELECT COUNT(*) FROM MyPersistedTable;
, la pensée est que le SGBD est susceptible de détenir des statistiques pour la cardinalité de la table.Par conséquent, parce que
COUNT(1)
etCOUNT(*)
sont sémantiquement équivalents, j'utiliseCOUNT(*)
.la source
COUNT(*)
etCOUNT(1)
sont les mêmes en cas de résultat et de performance.la source
Je m'attendrais à ce que l'optimiseur s'assure qu'il n'y a pas de réelle différence en dehors des cas de bord étranges.
Comme pour tout, la seule vraie façon de le savoir est de mesurer vos cas spécifiques.
Cela dit, je l'ai toujours utilisé
COUNT(*)
.la source
Comme cette question revient encore et encore, voici une réponse de plus. J'espère ajouter quelque chose pour les débutants qui s'interrogent sur les "meilleures pratiques" ici.
SELECT COUNT(*) FROM something
compte les enregistrements, ce qui est une tâche facile.SELECT COUNT(1) FROM something
récupère un 1 par enregistrement et compte ensuite les 1 qui ne sont pas nuls, ce qui revient essentiellement à compter les enregistrements, mais plus compliqué.Cela dit: Bon dbms notez que la deuxième instruction entraînera le même décompte que la première instruction et réinterprétez-le en conséquence, afin de ne pas faire de travail inutile. Donc, généralement, les deux instructions aboutiront au même plan d'exécution et prendront le même temps.
Cependant, du point de vue de la lisibilité, vous devez utiliser la première instruction. Vous voulez compter les enregistrements, donc compter les enregistrements, pas les expressions. Utilisez COUNT (expression) uniquement lorsque vous souhaitez compter les occurrences non nulles de quelque chose.
la source
J'ai effectué un test rapide sur SQL Server 2012 sur une boîte hyper-v de 8 Go de RAM. Vous pouvez voir les résultats par vous-même. Je n'exécutais aucune autre application fenêtrée en dehors de SQL Server Management Studio lors de l'exécution de ces tests.
Mon schéma de table:
Nombre total d'enregistrements dans le
Employee
tableau: 178090131 (~ 178 millions de lignes)Première requête:
Résultat de la première requête:
Deuxième requête:
Résultat de la deuxième requête:
Vous pouvez remarquer qu'il existe une différence de 83 (= 70265 - 70182) millisecondes qui peut facilement être attribuée à l'état exact du système au moment de l'exécution des requêtes. J'ai aussi fait un seul run, donc cette différence deviendra plus précise si je fais plusieurs runs et que je fais une moyenne. Si pour un ensemble de données aussi énorme, la différence est inférieure à 100 millisecondes, nous pouvons facilement conclure que les deux requêtes n'ont aucune différence de performances présentée par le moteur SQL Server.
Remarque : la RAM atteint près de 100% d'utilisation dans les deux exécutions. J'ai redémarré le service SQL Server avant de démarrer les deux exécutions.
la source
J'ai couru des centaines de fois, en effaçant le cache à chaque fois. Les résultats varient de temps en temps en fonction de la charge du serveur, mais ont presque toujours
count(*)
un temps processeur plus élevé.la source
count(*)
etcount(1)
retourner des résultats à quelques ms les uns des autres, même lors du comptage d'une table avec 4,5 millions de lignes, dans mon instance SQL 2008.Il y a un article montrant que
COUNT(1)
sur Oracle n'est qu'un aliasCOUNT(*)
, avec une preuve à ce sujet.Je citerai quelques parties:
Avec un utilisateur avec
ALTER SESSION
privilège, vous pouvez mettre untracefile_identifier
, activez le traçage optimiseur et exécutez laCOUNT(1)
sélection, comme:SELECT /* test-1 */ COUNT(1) FROM employees;
.Après cela, vous devez localiser les fichiers de trace, ce qui peut être fait avec
SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace';
. Plus loin dans le dossier, vous trouverez:Comme vous pouvez le voir, c'est juste un alias pour
COUNT(*)
.Autre commentaire important: le
COUNT(*)
était vraiment plus rapide il y a deux décennies sur Oracle, avant Oracle 7.3:Pour une autre base de données comme Sql Server, elle doit être recherchée individuellement pour chacune.
Je sais que cette question est spécifique à Sql Server, mais les autres questions sur SO sur le même sujet, sans mentionner la base de données, ont été fermées et marquées comme dupliquées de cette réponse.
la source
Dans tous les SGBDR, les deux méthodes de comptage sont équivalentes en termes de résultat qu'elles produisent. En ce qui concerne les performances, je n'ai observé aucune différence de performances dans SQL Server, mais il peut être utile de souligner que certains SGBDR, par exemple PostgreSQL 11, ont des implémentations moins optimales
COUNT(1)
car ils vérifient la nullité de l'expression d'argument comme on peut le voir dans ce billet .J'ai trouvé une différence de performances de 10% pour 1 million de lignes lors de l'exécution:
la source
COUNT (1) n'est pas très différent de COUNT (*), voire pas du tout. Quant à la question de COUNTing NULLable COLUMNs, cela peut être simple pour démontrer les différences entre COUNT (*) et COUNT (<certains col>) -
la source