Count (*) vs Count (1) - SQL Server
je me demande juste si l'un d'entre vous utilise Count(1)
au lieu de Count(*)
et s'il y a une différence notable dans la performance ou si c'est juste une habitude héritée qui a été avancée des jours passés?
(la base de données spécifique est SQL Server 2005
.)
11 réponses
Il n'y a pas de différence.
raison:
des Livres en ligne dit "
COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )
"
" 1 "est une expression non-nulle: donc c'est la même que COUNT(*)
.
L'optimizer le reconnaît pour ce qu'il est: trivial.
identique à EXISTS (SELECT * ...
ou EXISTS (SELECT 1 ...
exemple:
SELECT COUNT(1) FROM dbo.tab800krows
SELECT COUNT(1),FKID FROM dbo.tab800krows GROUP BY FKID
SELECT COUNT(*) FROM dbo.tab800krows
SELECT COUNT(*),FKID FROM dbo.tab800krows GROUP BY FKID
même IO, même plan, les travaux
Edit, Août 2011
question similaire sur DBA.SE .
Édition, Décembre 2011
COUNT(*)
est mentionné spécifiquement dans ANSI-92 (chercher " Scalar expressions 125
")
affaire:
a) Si COUNT (*) est spécifié, alors le résultat est la cardinalité de T.
C'est-à-dire, la norme ANSI reconnaît comme saignant évident ce que vous voulez dire. COUNT(1)
a été optimisé par les vendeurs RDBMS parce que de cette superstition. Dans le cas contraire, elle serait évaluée conformément à L'ANSI 151990920."
b) sinon, que TX soit le tableau à colonne unique qui est le résultat de l'application de l'expression
à chaque ligne de T et en éliminant les valeurs null. Si une ou plusieurs valeurs nulles être éliminé, une condition d'achèvement est soulevée: avertissement-
dans SQL Server, ces déclarations donnent les mêmes plans.
contrairement à l'opinion populaire, dans Oracle ils font aussi.
SYS_GUID()
dans Oracle est tout à fait fonction de calcul intensif.
dans ma base de données d'essai, t_even
est une table avec 1,000,000
lignes
Cette requête:
SELECT COUNT(SYS_GUID())
FROM t_even
s'exécute pour 48
secondes, puisque la fonction doit évaluer chaque SYS_GUID()
retourné pour s'assurer qu'il n'est pas un NULL
.
cependant, cette requête:
SELECT COUNT(*)
FROM (
SELECT SYS_GUID()
FROM t_even
)
s'exécute Pour mais 2
secondes, puisqu'il ne tente même pas d'évaluer SYS_GUID()
(malgré *
étant argument à COUNT(*)
)
de toute évidence, COUNT(*) et COUNT(1) vont toujours retourner le même résultat. Par conséquent, si l'un était plus lent que l'autre, il serait effectivement dû à un bug de l'optimiseur. Étant donné que les deux formulaires sont utilisés très fréquemment dans les requêtes, il ne serait pas logique qu'un SGBD permette à un tel bogue de ne pas être corrigé. Par conséquent, vous trouverez que la performance des deux formes est (probablement) identique dans tous les principaux DBMSs SQL.
dans la norme SQL-92, COUNT(*)
signifie spécifiquement" la cardinalité de l'expression de la table " (pourrait être une table de base, `VIEW, derived table, CTE, etc).
je suppose que l'idée était que COUNT(*)
est facile à analyser. L'utilisation de toute autre expression nécessite l'analyseur pour s'assurer qu'il ne se réfère à aucune colonne ( COUNT('a')
où a
est un littéral et COUNT(a)
où a
est une colonne peut donner des résultats différents).
dans la même veine, COUNT(*)
peut être facilement choisi par un codeur humain familier avec les normes SQL, une compétence utile lorsque l'on travaille avec plus d'une offre SQL d'un vendeur.
aussi , dans le cas particulier SELECT COUNT(*) FROM MyPersistedTable;
, la pensée est le SGBD est susceptible de détenir des statistiques pour la cardinalité de la table.
donc, parce que COUNT(1)
et COUNT(*)
sont sémantiquement équivalents, j'utilise COUNT(*)
.
COUNT(*)
et COUNT(1)
sont les mêmes en cas de résultat et de performance.
Je m'attends à ce que l'optimiseur s'assure qu'il n'y a pas de vraie différence en dehors des cas de bord bizarres.
comme pour tout, le seul vrai moyen de savoir est de mesurer vos cas spécifiques.
cela dit, j'ai toujours utilisé COUNT(*)
.
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 la "meilleure pratique" ici.
SELECT COUNT(*) FROM something
compte des enregistrements ce qui est une tâche facile.
SELECT COUNT(1) FROM something
extrait 1 par enregistrement et que compte le 1s qui ne sont pas null, qui est essentiellement comptage des enregistrements, plus complexe.
ceci dit: les bons SGBD remarquent que la deuxième déclaration résultera dans le même compte que la première déclaration et ré-interprètent en conséquence, comme ne pas faire de travail inutile. Ainsi, habituellement, les deux énoncés aboutiront au même plan d'exécution et prendront le même temps.
cependant, du point de lisibilité, vous devez utiliser le premier énoncé. Vous voulez compter les enregistrements, donc comptez les enregistrements, pas les expressions. Utilisez COUNT (expression) seulement quand vous voulez compter les occurences non-nulles de quelque chose.
j'ai fait un test rapide sur SQL Server 2012 sur une boite hyper-v RAM de 8 Go. Vous pouvez voir les résultats pour vous-même. Je n'ai pas exécuté d'autre application fendue en dehors de SQL Server Management Studio pendant l'exécution de ces tests.
mon schéma de table:
CREATE TABLE [dbo].[employee](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_employee] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
nombre Total d'enregistrements dans Employee
tableau: 178090131 (~178 millions de lignes)
Première Requête:
Set Statistics Time On
Go
Select Count(*) From Employee
Go
Set Statistics Time Off
Go
résultat de la première requête:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 35 ms.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 10766 ms, elapsed time = 70265 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
Deuxième Requête:
Set Statistics Time On
Go
Select Count(1) From Employee
Go
Set Statistics Time Off
Go
résultat de la deuxième requête:
SQL Server parse and compile time:
CPU time = 14 ms, elapsed time = 14 ms.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 11031 ms, elapsed time = 70182 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
vous pouvez remarquer qu'il y a une différence de 83 (= 70265 - 70182) millisecondes qui peut facilement être attribuée à l'état exact du système au moment où les requêtes sont exécutées. J'ai aussi fait une seule course, donc cette différence deviendra plus précise si je fais plusieurs descentes et si je fais une moyenne. Si pour un tel ensemble de données la différence est de moins de 100 millisecondes, alors nous pouvons facilement conclure que les deux requêtes n'ont aucune différence de performance démontrée par le moteur SQL Server.
Note : la RAM est utilisée à près de 100% dans les deux versions. J'ai redémarré le service SQL Server avant de commencer les deux cycles.
SET STATISTICS TIME ON
select count(1) from MyTable (nolock) -- table containing 1 million records.
l'Exécution de SQL Server Times:
Temps CPU = 31 ms, temps écoulé = 36 ms.
select count(*) from MyTable (nolock) -- table containing 1 million records.
l'Exécution de SQL Server Times:
Temps CPU = 46 ms, temps écoulé = 37 ms.
j'ai fait ça des centaines de fois, en nettoyant la cache à chaque fois.. Les résultats varient de temps en temps comme la charge du serveur varie, mais presque toujours count (*) a un temps cpu plus élevé.
il y a un article montrant que le COUNT(1)
sur Oracle est juste un alias à COUNT(*)
, avec un preuve à ce sujet.
je vais citer quelques parties:
Il ya une partie du logiciel de base de données qui s'appelle "le Optimizer", qui est défini dans la documentation officielle comme "Logiciel de base de données intégré qui détermine le moyen le plus efficace pour exécuter une instruction SQL".
l'Un des composants de l'optimiseur est appelé "le transformateur", dont le rôle est de déterminer s'il est avantageux de réécrire l' déclaration SQL originale dans une déclaration SQL sémantiquement équivalente qui pourrait être plus efficace.
aimeriez-vous voir ce que l'optimiseur ne lorsque vous écrivez une requête using COUNT (1)?
avec un utilisateur avec ALTER SESSION
Privilège, vous pouvez mettre un tracefile_identifier
, activer le traçage de l'optimiseur et exécuter le COUNT(1)
sélectionner, 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:
SELECT COUNT(*) “COUNT(1)” FROM “COURSE”.”EMPLOYEES” “EMPLOYEES”
Comme vous pouvez le voir, c'est juste un alias pour COUNT(*)
.
un autre commentaire important: le COUNT(*)
était vraiment plus rapide il y a deux décennies sur Oracle, avant Oracle 7.3:
Count (1) a été réécrit dans count(*) depuis 7.3 parce que Oracle comme pour régler automatiquement les déclarations mythiques. Dans Oracle7 plus tôt, oracle a dû evaluer (1) pour chaque ligne, en fonction, avant déterministe et Non déterministe existe.
donc il y a deux décennies, le compte (*) était plus rapide
pour une autre base de données en Sql Serveur, il doit être étudié individuellement pour chacun.
je sais que cette question est spécifique pour Sql Server, mais les autres questions sur SO sur le même sujet, sans mentionner la base de données, a été fermé et marqué comme dupliqué à partir de cette réponse.
Facile de faire la démonstration de COUNT(*) vs COUNT(
USE tempdb;
GO
IF OBJECT_ID( N'dbo.Blitzen', N'U') IS NOT NULL DROP TABLE dbo.Blitzen;
GO
CREATE TABLE dbo.Blitzen (ID INT NULL, Somelala CHAR(1) NULL);
INSERT dbo.Blitzen SELECT 1, 'A';
INSERT dbo.Blitzen SELECT NULL, NULL;
INSERT dbo.Blitzen SELECT NULL, 'A';
INSERT dbo.Blitzen SELECT 1, NULL;
SELECT COUNT(*), COUNT(1), COUNT(ID), COUNT(Somelala) FROM dbo.Blitzen;
GO
DROP TABLE dbo.Blitzen;
GO