web-dev-qa-db-fra.com

Existe-t-il une différence entre GROUP BY et DISTINCT

J'ai appris quelque chose de simple à propos de SQL l'autre jour:

SELECT c FROM myTbl GROUP BY C

A le même résultat que:

SELECT DISTINCT C FROM myTbl

Ce que je suis curieux de savoir, y a-t-il quelque chose de différent dans la façon dont un moteur SQL traite la commande ou s'agit-il vraiment de la même chose? 

Personnellement, je préfère la syntaxe distincte, mais je suis sûr que c'est plus par habitude que toute autre chose.

EDIT: Ce n'est pas une question sur les agrégats. L'utilisation de GROUP BY avec des fonctions d'agrégat est comprise.

251
Brettski

La réponse de { MusiGenesis } _ est fonctionnellement la bonne en ce qui concerne votre question, comme indiqué; SQL Server est suffisamment intelligent pour comprendre que si vous utilisez "Group By" et n'utilisez aucune fonction d'agrégat, vous voulez dire "Distinct" - et génère donc un plan d'exécution comme si vous aviez simplement utilisé "Distinct". . "

Cependant, je pense qu'il est important de noter également la réponse de Hank - un traitement cavalier de "Group By" et de "Distinct" pourrait conduire à des pièges pernicieux si vous ne faites pas attention. Il n'est pas tout à fait correct de dire qu'il ne s'agit "pas d'une question d'agrégats", car vous parlez de la différence fonctionnelle entre deux mots clés de requête SQL, l'un d'entre eux destiné à être utilisé avec des agrégats et l'autre de ne pas.

Un marteau peut parfois fonctionner pour enfoncer une vis, mais si vous avez un tournevis à portée de main, pourquoi s'en préoccuper?

(pour les besoins de cette analogie, Hammer : Screwdriver :: GroupBy : Distinct et screw => get list of unique values in a table column)

202
Skeolan

GROUP BY vous permet d'utiliser des fonctions d'agrégation, telles que AVG, MAX, MIN, SUM et COUNT. L'autre main DISTINCT supprime simplement les doublons.

Par exemple, si vous avez plusieurs enregistrements d’achat et que vous souhaitez savoir combien a été dépensé par chaque département, vous pouvez effectuer les opérations suivantes:

SELECT department, SUM(amount) FROM purchases GROUP BY department

Cela vous donnera une ligne par département, contenant le nom du département et la somme de toutes les valeurs amount de toutes les lignes de ce département.

125
Andru Luvisi

Il n'y a pas de différence (au moins dans SQL Server). Les deux requêtes utilisent le même plan d'exécution.

http://sqlmag.com/database-performance-tuning/distinct-vs-group

Peut-être y at-il une différence , s’il ya des sous-requêtes impliquées:

http://blog.sqlauthority.com/2007/03/29/sql-server-difference-between-distinct-and-group-by-distinct-vs-group-by/

Il n'y a pas de différence (style Oracle):

http://asktom.Oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:32961403234212

41
MusiGenesis

Utilisez DISTINCT si vous souhaitez simplement supprimer les doublons. Utilisez GROUPY BY si vous souhaitez appliquer des opérateurs agrégés (MAX, SUM, GROUP_CONCAT, ... ou une clause HAVING).

30
jkramer

Quelle est la différence d'un simple point de vue de la fonctionnalité de suppression des doublons

Mis à part le fait que, contrairement à DISTINCT, GROUP BY permet d’agréger les données par groupe (ce qui a été mentionné dans de nombreuses autres réponses), la différence la plus importante à mon avis est le fait que les deux opérations se produisent "à deux". différentes étapes de la ordre logique des opérations exécutées dans une instruction SELECT

Voici les opérations les plus importantes:

  • FROM (y compris JOIN, APPLY, etc.)
  • WHERE
  • GROUP BY(peut supprimer les doublons)
  • Agrégations
  • HAVING
  • Fonctions de la fenêtre
  • SELECT
  • DISTINCT(peut supprimer les doublons)
  • UNION, INTERSECT, EXCEPT(peut supprimer les doublons)
  • ORDER BY
  • OFFSET
  • LIMIT

Comme vous pouvez le constater, l'ordre logique de chaque opération influence ce que l'on peut en faire et comment il influence les opérations suivantes. En particulier, le fait que l'opération GROUP BY"se produise avant" l'opération SELECT (la projection) signifie que:

  1. Cela ne dépend pas de la projection (ce qui peut être un avantage)
  2. Il ne peut utiliser aucune valeur de la projection (ce qui peut être un inconvénient)

1. Cela ne dépend pas de la projection

Par exemple, ne pas dépendre de la projection est utile si vous souhaitez calculer des fonctions de fenêtre sur des valeurs distinctes:

SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating

Lorsqu'il est exécuté sur la base de données Sakila , cela donne:

rating   rn
-----------
G        1
NC-17    2
PG       3
PG-13    4
R        5

La même chose ne pourrait pas être réalisée avec DISTINCT facilement:

SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film

Cette requête est "fausse" et donne quelque chose comme:

rating   rn
------------
G        1
G        2
G        3
...
G        178
NC-17    179
NC-17    180
...

Ce n'est pas ce que nous voulions. L'opération DISTINCT"se produit après" la projection, nous ne pouvons donc plus supprimer les évaluations DISTINCT car la fonction window était déjà calculée et projetée. Pour utiliser DISTINCT, nous devrions imbriquer cette partie de la requête:

SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
  SELECT DISTINCT rating FROM film
) f

Note latérale: Dans ce cas particulier, nous pourrions aussi utiliser DENSE_RANK()

SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film

2. Il ne peut utiliser aucune valeur de la projection

L'un des inconvénients de SQL est sa verbosité parfois. Pour la même raison que ce que nous avons vu auparavant (à savoir l'ordre logique des opérations), nous ne pouvons pas "facilement" grouper par quelque chose que nous projetons.

Ceci n'est pas valide SQL:

SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY name

Ceci est valide (en répétant l'expression)

SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY first_name || ' ' || last_name

Ceci est également valable (imbriquer l'expression)

SELECT name
FROM (
  SELECT first_name || ' ' || last_name AS name
  FROM customer
) c
GROUP BY name

_ { J'ai écrit sur ce sujet de manière plus approfondie dans un article de blog } _

25
Lukas Eder

Je m'attends à ce qu'il y ait une possibilité de différences subtiles dans leur exécution ..__ J'ai vérifié les plans d'exécution pour deux requêtes équivalentes du point de vue de la fonctionnalité dans Oracle 10g:

core> select sta from Zip group by sta;

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    58 |   174 |    44  (19)| 00:00:01 |
|   1 |  HASH GROUP BY     |      |    58 |   174 |    44  (19)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| Zip  | 42303 |   123K|    38   (6)| 00:00:01 |
---------------------------------------------------------------------------

core> select distinct sta from Zip;

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    58 |   174 |    44  (19)| 00:00:01 |
|   1 |  HASH UNIQUE       |      |    58 |   174 |    44  (19)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| Zip  | 42303 |   123K|    38   (6)| 00:00:01 |
---------------------------------------------------------------------------

L'opération du milieu est légèrement différente: "HASH GROUP BY" ou "HASH UNIQUE", mais les coûts estimés, etc., sont identiques. J'ai ensuite exécuté celles-ci avec le traçage activé et les comptages d'opérations réels étaient les mêmes pour les deux (sauf que le second n'avait aucune lecture physique à cause de la mise en cache).

Mais je pense que parce que les noms d'opération sont différents, l'exécution suivrait des chemins de code quelque peu différents, ce qui ouvre la possibilité à des différences plus importantes.

Je pense que vous devriez préférer la syntaxe DISTINCT à cette fin. Ce n'est pas une habitude, cela indique plus clairement le but de la requête.

19
Dave Costa

Pour la requête que vous avez postée, elles sont identiques. Mais pour d'autres requêtes, cela peut ne pas être vrai.

Par exemple, ce n'est pas la même chose que:

SELECT C FROM myTbl GROUP BY C, D
14
Joel Coehoorn

J'ai lu tous les commentaires ci-dessus mais je n'ai vu personne indiquer la différence principale entre Group By et Distinct en dehors du bit d'agrégation.

Distinct renvoie toutes les lignes, puis les dédoublonne, tandis que Group By dédédupliquez les lignes au fur et à mesure de leur lecture par l'algorithme.

Cela signifie qu'ils peuvent produire des résultats différents!

Par exemple, les codes ci-dessous génèrent des résultats différents:

SELECT distinct ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable

 SELECT ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable
GROUP BY Name

S'il y a 10 noms dans la table dont 1 est un doublon d'un autre, la première requête renvoie 10 lignes tandis que la seconde interroge 9 lignes.

La raison est ce que j'ai dit ci-dessus afin qu'ils puissent se comporter différemment!

12
The Light

Ils ont une sémantique différente, même s’ils ont des résultats équivalents sur vos données.

11
Hank Gay

Si vous utilisez DISTINCT avec plusieurs colonnes, le jeu de résultats ne sera pas groupé comme avec GROUP BY et vous ne pouvez pas utiliser de fonctions d'agrégation avec DISTINCT.

11
Bill the Lizard

GROUP BY a une signification très spécifique qui est distincte (heh) de la fonction DISTINCT.

GROUP BY provoque le regroupement des résultats de la requête à l'aide de l'expression choisie. Des fonctions d'agrégation peuvent ensuite être appliquées. Celles-ci agissent sur chaque groupe plutôt que sur l'ensemble du résultat.

Voici un exemple qui pourrait aider:

Étant donné un tableau qui ressemble à ceci:

name
------
barry
dave
bill
dave
dave
barry
john

Cette requête:

SELECT name, count(*) AS count FROM table GROUP BY name;

Produira une sortie comme ceci:

name    count
-------------
barry   2
dave    3
bill    1
john    1

Ce qui est évidemment très différent de l'utilisation de DISTINCT. Si vous souhaitez grouper vos résultats, utilisez GROUP BY, si vous souhaitez uniquement une liste unique d'une colonne spécifique, utilisez DISTINCT. Cela permettra à votre base de données d'optimiser la requête en fonction de vos besoins.

5
Dan

N'utilisez pas GROUP BY lorsque vous voulez dire DISTINCT, même s'ils fonctionnent de la même manière. Je suppose que vous essayez d'économiser des millisecondes de requêtes, et je dois souligner que le temps passé par le développeur est beaucoup plus coûteux que le temps passé sur un ordinateur.

5
Andy Lester

Si vous utilisez un GROUP BY sans aucune fonction d'agrégat, il sera traité en interne comme DISTINCT. Par conséquent, dans ce cas, il n'y a pas de différence entre GROUP BY et DISTINCT.

Toutefois, lorsque la clause DISTINCT vous est fournie, il est préférable de l’utiliser pour rechercher vos enregistrements uniques car l’objectif de GROUP BY est d’obtenir une agrégation.

5
Vikram Mahapatra

group by est utilisé dans les opérations d'agrégation - comme lorsque vous souhaitez obtenir un nombre de Bs décomposé par la colonne C

select C, count(B) from myTbl group by C

distinct est ce que cela ressemble - vous obtenez des lignes uniques.

Dans SQL Server 2005, il semble que l'optimiseur de requêtes parvienne à optimiser la différence dans les exemples simplistes que j'ai exécutés. Je ne sais pas si vous pouvez compter sur cela dans toutes les situations.

4
Danimal

Dans cette requête particulière, il n'y a pas de différence. Mais, bien sûr, si vous ajoutez des colonnes agrégées, vous devrez utiliser group by.

3

Dans la perspective Teradata

Du point de vue du résultat, peu importe si vous utilisez DISTINCT ou GROUP BY dans Teradata. L'ensemble de réponses sera le même.

Du point de vue de la performance, ce n'est pas la même chose.

Pour comprendre l'impact sur les performances, vous devez savoir ce qui se passe sur Teradata lors de l'exécution d'une instruction avec DISTINCT ou GROUP BY.

Dans le cas de DISTINCT, les lignes sont immédiatement redistribuées sans aucune pré-agrégation, alors que dans le cas de GROUP BY, une pré-agrégation est effectuée et les valeurs uniques ne sont ensuite redistribuées que sur les AMP.

Ne pensez pas maintenant que GROUP BY est toujours meilleur du point de vue des performances. Lorsque vous avez plusieurs valeurs différentes, l'étape de pré-agrégation de GROUP BY n'est pas très efficace. Teradata doit trier les données pour éliminer les doublons. Dans ce cas, il peut être préférable de redistribuer d’abord, c’est-à-dire utiliser l’instruction DISTINCT. L'instruction GROUP BY est probablement le meilleur choix uniquement s'il existe de nombreuses valeurs en double, car une fois que l'étape de déduplication a lieu, après la redistribution. 

En bref, DISTINCT vs. GROUP BY dans Teradata signifie:

GROUP BY -> pour beaucoup de doublons DISTINCT -> pas ou peu de doublons. Parfois, lorsque vous utilisez DISTINCT, vous manquez d’espace de spool sur un amplificateur. La raison en est que la redistribution a lieu immédiatement et que des biais pourraient entraîner un manque d'espace pour les SAP. 

Dans ce cas, GROUP BY a probablement de meilleures chances, car les doublons sont déjà supprimés dans un premier temps et que moins de données sont déplacées entre les AMP.

2
Ram Ghadiyaram

Du point de vue du langage SQL, les deux constructions sont équivalentes et celle que vous choisissez est l'un de ces choix de «style de vie» que nous devons tous faire. Je pense qu'il est judicieux que DISTINCT soit plus explicite (et donc plus attentif à la personne qui héritera de votre code, etc.), mais cela ne signifie pas que la construction GROUP BY est un choix non valide. 

Je pense que ce «groupe par est pour les agrégats» est le mauvais accent. Les gens doivent être conscients que la fonction définie (MAX, MIN, COUNT, etc.) peut être omise afin de pouvoir comprendre l'intention du codeur à ce moment-là.

L'optimiseur idéal reconnaîtra les constructions SQL équivalentes et choisira toujours le plan idéal en conséquence. Pour votre moteur de choix SQL de la vie réelle, vous devez tester :)

PS note que la position du mot clé DISTINCT dans la clause select peut produire des résultats différents, par ex. contraste: 

SELECT COUNT(DISTINCT C) FROM myTbl;

SELECT DISTINCT COUNT(C) FROM myTbl;
2
onedaywhen

Je sais que c'est un ancien post. Mais il se trouve que j'avais une requête qui utilisait group en retournant simplement des valeurs distinctes lorsque crapaud et Oracle rapportait que tout fonctionnait bien, ce qui signifie un bon temps de réponse. Lorsque nous avons migré d’Oracle 9i à 11g, le temps de réponse dans Toad était excellent, mais dans le rapport, il fallait environ 35 minutes pour terminer le rapport; lorsqu’il utilisait la version précédente, il prenait environ 5 minutes.

La solution consistait à changer de groupe et à utiliser DISTINCT. Le rapport s’exécute maintenant en 30 secondes environ.

J'espère que cela est utile pour quelqu'un avec la même situation.

1
Gabriel

Vous ne le remarquez que parce que vous sélectionnez une seule colonne.

Essayez de sélectionner deux champs et voyez ce qui se passe.

Group By est destiné à être utilisé comme ceci:

SELECT name, SUM(transaction) FROM myTbl GROUP BY name

Ce qui montrerait la somme de toutes les transactions pour chaque personne.

1
Chris Cudmore

L'efficacité fonctionnelle est totalement différente. Si vous souhaitez uniquement sélectionner "valeur de retour", sauf dupliquer, utilisez distinct mieux que grouper par. Parce que "grouper par" inclut (trie + supprime), "distinct" inclut (supprime) 

0
Jun

Parfois, ils peuvent vous donner les mêmes résultats, mais ils doivent être utilisés dans un sens différent. La principale différence réside dans la syntaxe.

Notez attentivement l'exemple ci-dessous. DISTINCT est utilisé pour filtrer le jeu de valeurs en double. (6, cs, 9.1) et (1, cs, 5.5) sont deux ensembles différents. Donc, DISTINCT va afficher les deux lignes tandis que GROUP BY Branch ne va afficher qu'un seul jeu.

 SELECT * FROM student; 
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    2 | mech   |  6.3 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    1 | cs     |  5.5 |
+------+--------+------+
5 rows in set (0.001 sec)

SELECT DISTINCT * FROM student; 
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    2 | mech   |  6.3 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    1 | cs     |  5.5 |
+------+--------+------+
5 rows in set (0.001 sec)

SELECT * FROM student GROUP BY Branch;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    2 | mech   |  6.3 |
+------+--------+------+
4 rows in set (0.001 sec)

Parfois, les résultats pouvant être obtenus avec la clause GROUP BY ne sont pas possibles avec la méthode DISTINCT sans utiliser de clause ou de conditions supplémentaires. E.g dans le cas ci-dessus.

Pour obtenir le même résultat que DISTINCT, vous devez transmettre tous les noms de colonnes de la clause GROUP BY comme ci-dessous. Alors voyez la différence syntaxique. Vous devez connaître tous les noms de colonne pour pouvoir utiliser la clause GROUP BY dans ce cas.

SELECT * FROM student GROUP BY Id, Branch, CGPA;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    1 | cs     |  5.5 |
|    2 | mech   |  6.3 |
|    3 | civil  |  7.2 |
|    4 | eee    |  8.2 |
|    6 | cs     |  9.1 |
+------+--------+------+

J'ai aussi remarqué que GROUP BY affiche les résultats par défaut dans l'ordre croissant, ce que DISTINCT ne fait pas. Mais je ne suis pas sûr de cela. Il peut être différent du vendeur.

Source: https://dbjpanda.me/dbms/languages/sql/sql-syntax-with-examples#group-by

0
SkyRar

Généralement, nous pouvons utiliser DISTINCT pour éliminer les doublons sur une colonne spécifique du tableau.

Dans le cas de 'GROUP BY', nous pouvons appliquer les fonctions d'agrégation telles que AVG, MAX, MIN, SUM et COUNT sur une colonne spécifique et récupérer le nom de colonne et la fonction d'agrégation résultent sur la même colonne.

Exemple :

select  specialColumn,sum(specialColumn) from yourTableName group by specialColumn;
0
Lova Chittumuri

Dans Hive (HQL), group by peut être beaucoup plus rapide que distinct, car le premier ne nécessite pas de comparer tous les champs de la table. Voir https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct .

0
John Jiang

J'avais cette question auparavant, je dois ajouter trois colonnes de mon tableau de 4 millions de lignes (les trois colonnes dans une nouvelle colonne d'un nouveau tableau), mais uniquement les différentes. 

J'ai donc exécuté ma procédure stockée qui contient cette requête avec la méthode 'group by' et cela a pris 32 minutes. Ensuite, je l'ai relancé, mais avec la méthode "distincte" et cela a pris 25 minutes. 

C'est le même résultat, mais c'était un peu plus rapide avec la 2ème méthode

0
Pedro Ivan

J'ai toujours compris que l'utilisation de distinct correspond à un regroupement de chaque champ sélectionné dans l'ordre choisi. 

c'est à dire:

select distinct a, b, c from table;

est le même que:

select a, b, c from table group by a, b, c
0
Zenshai