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
?
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!
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
.
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!
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!
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 ... :)
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
Il semble que les requêtes ne sont pas exactement les mêmes. Du moins pour MySQL.
Comparer:
La deuxième requête donne en plus "Utilisation du port de fichiers" dans Extra.
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.
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.
(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!)
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)
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
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.
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.
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.