¿Qué es más rápido, SELECT DISTINCT o GROUP BY en MySQL?

273

Si tengo una mesa

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)
)

y quiero obtener todos los valores únicos de professioncampo, lo que sería más rápido (o recomendado):

SELECT DISTINCT u.profession FROM users u

o

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

?

vava
fuente
2
Podrías hacerte una prueba tan rápido como hacer la pregunta. Irritantemente, es casi imposible construir un escenario en el que DISTINCT supere a GROUP BY, lo cual es molesto porque claramente este no es el propósito de GROUP BY. Sin embargo, GROUP BY puede producir resultados engañosos, lo cual creo que es razón suficiente para evitarlo.
Fresa
Hay otro duplicado con una respuesta diferente. ver MySql - Distinct vs Group By <<< dice que GROUP BY es mejor
kolunar
Consulte aquí si desea medir la diferencia horaria entre DISTINCT y GROUP BY ejecutando su consulta.
kolunar

Respuestas:

258

Son esencialmente equivalentes entre sí (de hecho, así es como algunas bases de datos se implementan DISTINCTbajo el capó).

Si uno de ellos es más rápido, lo será DISTINCT. Esto se debe a que, aunque los dos son iguales, un optimizador de consultas debería detectar el hecho de que GROUP BYno se está aprovechando de ningún miembro del grupo, solo de sus claves. DISTINCTlo hace explícito, para que pueda salirse con la suya con un optimizador ligeramente más tonto.

En caso de duda, prueba!

SquareCog
fuente
76
DISTINCT será más rápido solo si NO tiene un índice (ya que no se clasifica). Cuando tienes un índice y se usa, son sinónimos.
Quassnoi
10
La definición de DISTINCTy GROUP BYdifieren en eso DISTINCTno tiene que ordenar la salida, y GROUP BYpor defecto sí. Sin embargo, en MySQL, incluso un DISTINCT+ ORDER BYpodría ser aún más rápido que GROUP BYdebido a las sugerencias adicionales para el optimizador como lo explica SquareCog.
rustyx
1
DISTINCT es mucho más rápido con gran cantidad de datos.
Pankaj Wanjari
77
Probé esto y descubrí que en una columna indexada, mysql, group by era aproximadamente 6 veces más lento que distinto con una consulta bastante complicada. Solo agrego esto como un punto de datos. Cerca de 100k filas. Así que pruébalo y compruébalo.
Lizardx
ver MySql - Distinct vs Group By <<< dice que GROUP BY es mejor
kolunar
100

Si tiene un índice profession, estos dos son sinónimos.

Si no lo haces, entonces úsalo DISTINCT.

GROUP BYen MySQLespecie resultados. Incluso puedes hacer:

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

y ordena tus profesiones en DESCorden.

DISTINCTcrea una tabla temporal y la usa para almacenar duplicados. GROUP BYhace lo mismo, pero sortes los resultados distintos después.

Entonces

SELECT DISTINCT u.profession FROM users u

es más rápido si no tiene un índice activado profession.

Quassnoi
fuente
66
Puede agregar ORDER BY NULLal GROUP BYpara evitar el orden.
Ariel
Aún más lento incluso con la agrupación por nulo
Thanh Trung
@ThanhTrung: ¿qué es más lento que qué?
Quassnoi
@Quassnoi groupby más lento que distinto incluso si se evita la clasificación
Thanh Trung
Nota: Los calificadores de pedidos en GROUP BY quedaron en desuso en MySQL 8.
Matthew Lenz
18

Todas las respuestas anteriores son correctas, para el caso de DISTINCT en una sola columna vs GROUP BY en una sola columna. Cada motor db tiene su propia implementación y optimizaciones, y si le importa la muy pequeña diferencia (en la mayoría de los casos), ¡entonces tiene que probar con un servidor específico Y una versión específica! Como las implementaciones pueden cambiar ...

PERO, si selecciona más de una columna en la consulta, ¡entonces DISTINCT es esencialmente diferente! Porque en este caso comparará TODAS las columnas de todas las filas, en lugar de solo una columna.

Entonces, si tienes algo como:

// 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

Es un error común pensar que la palabra clave DISTINCT distingue filas por la primera columna que especificó, pero DISTINCT es una palabra clave general de esta manera.

Por lo tanto, debe tener cuidado de no tomar las respuestas anteriores como correctas para todos los casos ... ¡Podría confundirse y obtener los resultados incorrectos mientras que todo lo que quería era optimizar!

daniel.gindi
fuente
3
Aunque esta pregunta es sobre MySQL, debe tenerse en cuenta que la segunda consulta solo funcionará en MySQL. Casi todos los demás DBMS rechazarán la segunda declaración porque es un uso no válido del operador GROUP BY.
a_horse_with_no_name
Bueno, "casi" es una definición problemática :-) Sería mucho más útil si declaras un DBMS específico que has probado para ver que genera un error para esta declaración.
daniel.gindi
3
Postgres, Oracle, Firebird, DB2, SQL Server para empezar. MySQL: sqlfiddle.com/#!2/6897c/1 Postgres: sqlfiddle.com/#!12/6897c/1 Oracle: sqlfiddle.com/#!12/6897c/1 SQL Server: sqlfiddle.com/#!6/ 6897c / 1
a_horse_with_no_name
17

Elija lo más simple y lo más breve posible: DISTINCT parece ser más lo que está buscando solo porque le dará EXACTAMENTE la respuesta que necesita y ¡solo eso!

Tim
fuente
7

Agrupar por es costoso que Distinct ya que Agrupar por hace una clasificación del resultado mientras que distinto lo evita. Pero si desea hacer que group by produce el mismo resultado que distinto, ordene por nulo .

SELECT DISTINCT u.profession FROM users u

es igual a

SELECT u.profession FROM users u GROUP BY u.profession order by null
Ranjith
fuente
es igual aSELECT profession FROM users GROUP BY profession
6

bien distinto puede ser más lento que el grupo en algunas ocasiones en postgres (no sé sobre otros dbs).

ejemplo probado:

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

así que ten cuidado ... :)

OptilabWorker
fuente
5

Parece que las consultas no son exactamente las mismas. Al menos para MySQL.

Comparar:

  1. describa el nombre del producto seleccionado de northwind.products
  2. describa el nombre del producto seleccionado del grupo northwind.products por nombre del producto

La segunda consulta proporciona adicionalmente "Uso de ordenar archivos" en Extra.

amartynov
fuente
1
Son lo mismo en términos de lo que obtienen, no en términos de cómo lo obtienen. Un optimizador ideal los ejecutaría de la misma manera, pero el optimizador MySQL no es ideal. Según su evidencia, parece que DISTINCT iría más rápido: O (n) frente a O (n * log n).
SquareCog
Entonces, ¿"usar filesort" es esencialmente malo?
vava
En este caso lo es, porque no necesita ordenar (lo haría si necesitara los grupos). MySQL ordena para colocar las mismas entradas juntas, y luego obtener grupos escaneando el archivo ordenado. Solo necesita distinciones, por lo que solo tiene que hacer hash de sus claves mientras realiza un escaneo de una sola tabla.
SquareCog
1
Agregue ORDER BY NULLa la GROUP BYversión y serán lo mismo.
Ariel
3

En MySQL , " Group By" utiliza un paso adicional: filesort. Me doy cuenta de que DISTINCTes más rápido que GROUP BYeso, y eso fue una sorpresa.

Carlos
fuente
3

Después de muchas pruebas, llegamos a la conclusión de que GROUP BY es más rápido

SELECCIONE sql_no_cache opnamegroep_intern DESDE telwerken DONDE opnemergroep(7,8,9,10,11,12,13) ​​grupo por opnamegroep_intern

635 total 0,0944 segundos Weergave van registra 0-29 (635 total, consulta duurde 0,0484 segundos)

SELECCIONE sql_no_cache distinct (opnamegroep_intern) DESDE telwerken DONDE opnemergroepEN (7,8,9,10,11,12,13)

635 total 0.2117 segundos (casi 100% más lento) Weergave van registra 0-29 (635 total, consulta duurde 0.3468 seg)

Gruñón
fuente
2

(más de una nota funcional)

Hay casos en los que tiene que usar GROUP BY, por ejemplo, si desea obtener el número de empleados por empleador:

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

En tal escenario DISTINCT u.employerno funciona bien. Quizás haya un camino, pero simplemente no lo sé. (Si alguien sabe cómo hacer una consulta con DISTINCT, ¡agregue una nota!)

Ivan Dossev
fuente
2

Aquí hay un enfoque simple que imprimirá los 2 tiempos transcurridos diferentes para cada consulta.

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);

O pruebe 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;

Simplemente muestra el número de milisegundos necesarios para analizar, compilar y ejecutar cada instrucción de la siguiente manera:

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

Esto no es una regla

Para cada consulta ... intente por separado y luego agrupe por ... compare el tiempo para completar cada consulta y use el más rápido ...

En mi proyecto, a veces uso group by y otros distintos

usuario2832991
fuente
0

Si no tiene que hacer ninguna función de grupo (suma, promedio, etc. en caso de que desee agregar datos numéricos a la tabla), use SELECT DISTINCT. Sospecho que es más rápido, pero no tengo nada que mostrar.

En cualquier caso, si le preocupa la velocidad, cree un índice en la columna.

Tehvan
fuente
0

SELECT DISTINCT siempre será el mismo, o más rápido, que GROUP BY. En algunos sistemas (es decir, Oracle), puede estar optimizado para ser el mismo que DISTINCT para la mayoría de las consultas. En otros (como SQL Server), puede ser considerablemente más rápido.

Bip bip
fuente
0

Si el problema lo permite, intente con EXISTS, ya que está optimizado para terminar tan pronto como se encuentre un resultado (y no almacene ninguna respuesta), por lo tanto, si solo está tratando de normalizar los datos para una cláusula WHERE como esta

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

Una respuesta más rápida sería:

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

Esto no siempre es posible, pero cuando esté disponible, verá una respuesta más rápida.

Daniel R
fuente