web-dev-qa-db-fra.com

Quoi de plus rapide, SELECT DISTINCT ou GROUP BY dans MySQL?

Si j'ai une table

CREATE TABLE users (
  id int(10) unsigned NOT NULL auto_increment,
  name varchar(255) NOT NULL,
  profession varchar(255) NOT NULL,
  employer varchar(255) NOT NULL,
  PRIMARY KEY  (id)
)

et je veux obtenir toutes les valeurs uniques du champ profession, ce qui serait plus rapide (ou recommandé):

SELECT DISTINCT u.profession FROM users u

ou

SELECT u.profession FROM users u GROUP BY u.profession

?

260
vava

Elles sont essentiellement équivalentes (en fait, certaines bases de données implémentent DISTINCT sous le capot).

Si l'un d'eux est plus rapide, il s'agira de DISTINCT. En effet, bien que les deux soient identiques, un optimiseur de requête devrait prendre en compte le fait que votre GROUP BY ne tire pas parti des membres du groupe, mais seulement de leurs clés. DISTINCT rend ceci explicite, vous pouvez donc vous en tirer avec un optimiseur légèrement plus bête.

En cas de doute, testez!

238
SquareCog

Si vous avez un index sur profession, ces deux sont synonymes.

Sinon, utilisez DISTINCT.

GROUP BY dans MySQL trie les résultats. Vous pouvez même faire:

SELECT u.profession FROM users u GROUP BY u.profession DESC

et obtenez vos professions triées dans l'ordre DESC.

DISTINCT crée une table temporaire et l'utilise pour stocker les doublons. GROUP BY fait la même chose, mais retient les résultats distincts par la suite.

Alors

SELECT DISTINCT u.profession FROM users u

est plus rapide si vous n'avez pas d'index sur profession.

98
Quassnoi

Si vous le pouvez, optez pour le plus simple et le plus court - DISTINCT semble être ce que vous recherchez uniquement parce que cela vous donnera EXACTEMENT la réponse dont vous avez besoin et rien que cela!

17
Tim

Toutes les réponses ci-dessus sont correctes, pour le cas de DISTINCT sur une seule colonne vs GROUP BY sur une seule colonne. Chaque moteur de base de données a ses propres implémentations et optimisations, et si vous vous souciez de la très petite différence (dans la plupart des cas), vous devez tester le serveur ET la version de votre choix! Comme les implémentations peuvent changer ...

MAIS, si vous sélectionnez plus d'une colonne dans la requête, alors le DISTINCT est essentiellement différent! Parce que dans ce cas, il comparera TOUTES les colonnes de toutes les lignes, au lieu d’une seule colonne.

Donc, si vous avez quelque chose comme:

// This will NOT return unique by [id], but unique by (id,name)
SELECT DISTINCT id, name FROM some_query_with_joins

// This will select unique by [id].
SELECT id, name FROM some_query_with_joins GROUP BY id

C'est une erreur courante de penser que le mot clé DISTINCT distingue les lignes de la première colonne que vous avez spécifiée, mais le mot clé DISTINCT est un mot clé général de cette manière.

Il faut donc veiller à ne pas prendre les réponses ci-dessus comme étant correctes dans tous les cas ... Vous pourriez vous perdre et obtenir de mauvais résultats alors que tout ce que vous souhaitiez était d'optimiser!

16
daniel.gindi

bien distinct peut être plus lent que le groupe par à certaines occasions dans postgres (ne sais pas sur d'autres dbs).

exemple testé:

postgres=# select count(*) from (select distinct i from g) a;

count 

10001
(1 row)

Time: 1563,109 ms

postgres=# select count(*) from (select i from g group by i) a;

count
10001
(1 row)

Time: 594,481 ms

http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I

donc sois prudent ... :)

7
OptilabWorker

Grouper est plus cher que Distinct puisque Group by effectue un tri sur le résultat alors que distinct l'évite. Mais si vous voulez que groupe donne le même résultat que donner order by null ..

SELECT DISTINCT u.profession FROM users u

est égal à

SELECT u.profession FROM users u GROUP BY u.profession order by null
7
Ranjith

Il semble que les requêtes ne sont pas exactement les mêmes. Du moins pour MySQL.

Comparer:

  1. décrivent une sélection de nom de produit distinct de northwind.products
  2. décrit le nom du produit sélectionné à partir de northwind.products groupe par nom du produit

La deuxième requête donne en plus "Utilisation du port de fichiers" dans Extra.

5
amartynov

Dans MySQL, "Group By" utilise une étape supplémentaire: filesort. Je réalise que DISTINCT est plus rapide que GROUP BY, et c'était une surprise.

3
Carlos

Voici une approche simple qui imprimera les 2 temps écoulés différents pour chaque requête.

DECLARE @t1 DATETIME;
DECLARE @t2 DATETIME;

SET @t1 = GETDATE();
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
SET @t2 = GETDATE();
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);

SET @t1 = GETDATE();
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
SET @t2 = GETDATE();
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);

OU essayez SET STATISTICS TIME (Transact-SQL)

SET STATISTICS TIME ON;
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
SET STATISTICS TIME OFF;

Il affiche simplement le nombre de millisecondes requis pour analyser, compiler et exécuter chaque instruction comme ci-dessous:

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 2 ms.
2
kolunar

(plus d'une note fonctionnelle)

Dans certains cas, vous devez utiliser GROUP BY, par exemple si vous souhaitez obtenir le nombre d'employés par employeur:

SELECT u.employer, COUNT(u.id) AS "total employees" FROM users u GROUP BY u.employer

Dans un tel scénario, DISTINCT u.employer ne fonctionne pas correctement. Peut-être y a-t-il un moyen, mais je ne le sais tout simplement pas. (Si quelqu'un sait comment faire une telle requête avec DISTINCT, ajoutez une note!)

2
Ivan Dossev

Après des tests intensifs, nous avons conclu que GROUP BY est plus rapide

SELECT sql_no_cache opnamegroep_intern FROM telwerken LIEU opnemergroep IN (7,8,9,10,11,12,13) ​​groupe par opnamegroep_intern

635 totales 0.0944 secondes Weergave van records 0 - 29 (635 totales, requête du moment 0.0484 sec)

SELECT sql_no_cache distinct (opnamegroep_intern) FROM telwerken WHERE opnemergroep IN (7,8,9,10,11,12,13)

635 totales 0,2117 secondes (presque 100% plus lent) Weergave van enregistrements 0 - 29 (635 totales, requête du moins de 0.3468 sec)

1
Grumpy

Ce n'est pas une règle

Pour chaque requête .... essayez séparément, puis groupe par ... comparez le temps nécessaire pour compléter chaque requête et utilisez la plus rapide ....

Dans mon projet, j’utilise parfois group by by et distinct

1
user2832991

Si le problème le permet, essayez avec EXISTS, car il est optimisé pour se terminer dès qu'un résultat est trouvé (et ne mettez pas de mémoire tampon en réponse), donc, si vous essayez simplement de normaliser les données pour une clause WHERE comme celle-ci

SELECT FROM SOMETHING S WHERE S.ID IN ( SELECT DISTINCT DCR.SOMETHING_ID FROM DIFF_CARDINALITY_RELATIONSHIP DCR ) -- to keep same cardinality

Une réponse plus rapide serait:

SELECT FROM SOMETHING S WHERE EXISTS ( SELECT 1 FROM DIFF_CARDINALITY_RELATIONSHIP DCR WHERE DCR.SOMETHING_ID = S.ID )

Ce n'est pas toujours possible, mais une fois disponible, vous obtiendrez une réponse plus rapide.

0
Daniel R

SELECT DISTINCT sera toujours identique ou plus rapide qu’un GROUP BY. Sur certains systèmes (par exemple, Oracle), il peut être optimisé pour être identique à DISTINCT pour la plupart des requêtes. Sur d'autres (tels que SQL Server), cela peut être considérablement plus rapide.

0
Beep beep

Si vous ne devez effectuer aucune fonction de groupe (somme, moyenne, etc. si vous souhaitez ajouter des données numériques à la table), utilisez SELECT DISTINCT. Je suppose que c'est plus rapide, mais je n'ai rien à montrer.

Dans tous les cas, si la vitesse vous inquiète, créez un index sur la colonne.

0
tehvan