t-sql GROUP BY avec COUNT, puis inclure MAX du COUNT
Supposons que vous ayez une table de "Voitures" avec des centaines de milliers de lignes,
et tu voulais faire un GROUPE PAR:
SELECT CarID
, CarName
, COUNT(*) AS Total
FROM dbo.tbl_Cars
GROUP BY CarID
, CarName
Le groupement vous laisse avec un résultat semblable à:
CarID CarName Total
1872 Olds 202,121
547841 BMW 175,298
9877 Ford 10,241
Tous très bien et bien.
Ma question, cependant, est ce qui est le meilleur moyen pour obtenir le
Total et la Totale maximum dans un tableau, en termes de performance et de
le codage propre, de sorte que vous avez un résultat comme:
CarID CarName Total Max Total
1872 Olds 202,121 202,121
547841 BMW 175,298 202,121
9877 Ford 10,241 202,121
Une approche pourrait être de mettre le résultat du GROUPE dans une table temporaire,
et puis obtenir le MAX de la table temporaire dans une variable locale.
Mais je me demandais quelle est la meilleure façon de le faire serait.
Mise à JOUR
L'Expression de Table Commune semble le plus élégant d'écrire,
pourtant, similaire à @EBarr, mon test limitée, indique nettement une baisse des performances.
Donc je ne vais pas aller avec le CTE.
Que le link @EBarr a pour le COMPUTE
option indique que la fonction
est obsolète, qui ne semble pas le meilleur itinéraire.
L'option d'une variable locale pour la valeur MAX et l'utilisation de
une table temporaire sera probablement la route, je descends, je ne suis pas
conscient des problèmes de performances avec elle.
Un peu plus de détails sur mon cas d'utilisation: il pourrait probablement être un
série d'autres questions. Mais il suffit de dire que je suis de chargement
un grand sous-ensemble de données dans une table temporaire (donc un sous-ensemble de tbl_Cars est
aller dans #tbl_Cars, et même #tbl_Cars peut être filtré
et ont agrégations effectuées sur elle), parce que j'ai effectuer plusieurs filtrage
et l'agrégation des requêtes dans une seule procédure stockée
renvoie plusieurs jeux de résultats.
Mise à JOUR 2
@EBarr de l'utilisation d'une fenêtre de la fonction est belle et courte. Note à moi-même:
si vous utilisez un RIGHT JOIN
à l'extérieur de la table de référence, le COUNT()
la fonction doit sélectionner une colonne de tbl_Cars, pas '*'
.
SELECT M.MachineID
, M.MachineType
, COUNT(C.CarID) AS Total
, MAX(COUNT(C.CarID)) OVER() as MaxTotal
FROM dbo.tbl_Cars C
RIGHT JOIN dbo.tbl_Machines M
ON C.CarID = M.CarID
GROUP BY M.MachineID
, M.MachineType
En termes de vitesse, il semble bien, mais à quel point avez-vous d'être
inquiet de voir le nombre de lectures?
source d'informationauteur mg1075
Vous devez vous connecter pour publier un commentaire.
Mécaniquement, il ya quelques façons de le faire. Vous pouvez utiliser des tables temporaires/variable de table. Une autre façon est avec des requêtes imbriquées et/ou un CTE @Aaron_Bertrand a montré. Une troisième façon est d'utiliser la FENÊTRE des FONCTIONS telles que...
Un non grata (lire depricated) quatrième moyen est d'utiliser le CALCUL de mot-clé en tant que tel...
La
COMPUTE
mot-clé génère totaux qui apparaissent comme complémentaires colonnes de synthèse à la fin de l'ensemble de résultats (voir ce). Dans la requête ci-dessus, vous en fait voir de deux ensembles d'enregistrements.Plus rapide
Maintenant, la prochaine question est, quel est le "meilleur/le plus rapide/la plus facile." Je pense tout de suite à un
indexed view
. @Aaron doucement m'a rappelé, les vues indexées ont toutes sortes de restrictions. Ci-dessus, la stratégie, cependant, vous permet de créer une vue indexée sur le SELECT...from..GROUPE. Puis en sélectionnant à partir de la vue indexée appliquer le mode FENÊTRÉ clause de FONCTION.Sans en savoir plus, cependant, à propos de votre design, il va être difficile pour quiconque de vous dire ce qui est le meilleur. Vous obtiendrez d'éclairage rapide des requêtes à partir d'une vue indexée. Cette performance a un prix, cependant. Le prix est frais de maintenance. Si la table sous-jacente est la cible d'une grande quantité d'insérer/mettre à jour/supprimer des opérations de la maintenance de la vue indexée ralentisse la performance dans d'autres domaines.
Si vous partagez un peu plus sur votre cas d'utilisation, de données et de modèles d'accès de gens seront en mesure de partager plus de perspicacité.
MICRO TEST DE PERFORMANCE
J'ai donc généré un peu de données de script et regarda le générateur de profils sql numéros de la CTE de la performance vs fenêtré fonctions. C'est un micro-test, alors essayez certains des nombres réels votre système sous de charge réel.
La génération de données:
Ce script génère 10 000 lignes. J'ai ensuite couru chacun des quatre requêtes suivantes à plusieurs reprises :
Après l'exécution de la ci-dessus requêtes, j'ai créé une vue indexée sur le "groupe" de la requête ci-dessus. Ensuite, j'ai couru une requête sur la vue indexée qui a effectué un
MAX(Count(*)) OVER(PARTITION BY 'foo'
.LA MOYENNE DES RÉSULTATS
Évidemment, c'est un micro-benchmark et seulement légèrement instructif, afin de les prendre pour ce qu'elle vaut.
Voici un moyen:
SQL Server 2008 R2 et les versions plus récentes, vous pouvez utiliser :