sql - ejemplos - ¿Hay alguna diferencia entre GROUP BY y DISTINCT?
group by mysql (24)
¿Cuál es la diferencia de un mero punto de vista de la funcionalidad de eliminación duplicada?
Aparte del hecho de que, a diferencia de DISTINCT
, GROUP BY
permite agregar datos por grupo (lo que se ha mencionado en muchas otras respuestas), la diferencia más importante en mi opinión es el hecho de que las dos operaciones "suceden" en dos pasos muy diferentes. el orden lógico de las operaciones que se ejecutan en una instrucción SELECT
.
Aquí están las operaciones más importantes:
-
FROM
(incluyendoJOIN
,APPLY
, etc.) -
WHERE
-
GROUP BY
(puede eliminar duplicados) - Agregaciones
-
HAVING
- Funciones de ventana
-
SELECT
-
DISTINCT
(puede eliminar duplicados) -
UNION
,INTERSECT
,EXCEPT
(puede eliminar duplicados) -
ORDER BY
-
OFFSET
-
LIMIT
Como puede ver, el orden lógico de cada operación influye en lo que se puede hacer con ella y cómo influye en las operaciones subsiguientes. En particular, el hecho de que la operación GROUP BY
"ocurra antes" de la operación SELECT
(la proyección) significa que:
- No depende de la proyección (lo que puede ser una ventaja)
- No puede usar ningún valor de la proyección (lo que puede ser una desventaja)
1. No depende de la proyección.
Un ejemplo en el que no es útil depender de la proyección es si desea calcular las funciones de la ventana en valores distintos:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating
Cuando se ejecuta contra la base de datos de Sakila , esto produce:
rating rn
-----------
G 1
NC-17 2
PG 3
PG-13 4
R 5
Lo mismo no se puede lograr con DISTINCT
fácilmente:
SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
Esa consulta es "incorrecta" y produce algo como:
rating rn
------------
G 1
G 2
G 3
...
G 178
NC-17 179
NC-17 180
...
Esto no es lo que queríamos. La operación DISTINCT
"ocurre después de" la proyección, por lo que ya no podemos eliminar las calificaciones DISTINCT
porque la función de ventana ya se había calculado y proyectado. Para utilizar DISTINCT
, tendríamos que anidar esa parte de la consulta:
SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
SELECT DISTINCT rating FROM film
) f
Nota al margen: en este caso particular, también podríamos usar DENSE_RANK()
SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film
2. No puede utilizar ningún valor de la proyección.
Uno de los inconvenientes de SQL es su verbosidad a veces. Por la misma razón que hemos visto antes (es decir, el orden lógico de las operaciones), no podemos "fácilmente" agrupar por algo que estamos proyectando.
Esto no es válido SQL:
SELECT first_name || '' '' || last_name AS name
FROM customer
GROUP BY name
Esto es válido (repitiendo la expresión)
SELECT first_name || '' '' || last_name AS name
FROM customer
GROUP BY first_name || '' '' || last_name
Esto también es válido (anidando la expresión)
SELECT name
FROM (
SELECT first_name || '' '' || last_name AS name
FROM customer
) c
GROUP BY name
He escrito más a fondo sobre este tema en una publicación de blog.
Aprendí algo simple sobre SQL el otro día:
SELECT c FROM myTbl GROUP BY C
Tiene el mismo resultado que:
SELECT DISTINCT C FROM myTbl
De lo que tengo curiosidad, ¿hay algo diferente en la forma en que un motor de SQL procesa el comando, o son realmente lo mismo?
Personalmente prefiero la sintaxis distinta, pero estoy seguro de que es más por costumbre que por cualquier otra cosa.
EDITAR: Esta no es una pregunta sobre agregados. Se entiende el uso de GROUP BY
con funciones agregadas.
Agrupar por se usa en operaciones agregadas, como cuando se desea obtener un recuento de Bs desglosado por la columna C
select C, count(B) from myTbl group by C
distinto es lo que suena: obtienes filas únicas.
En el servidor SQL 2005, parece que el optimizador de consultas puede optimizar la diferencia en los ejemplos simplistas que ejecuté. Pero no sé si puedes contar con eso en todas las situaciones.
Desde la perspectiva del "lenguaje SQL", las dos construcciones son equivalentes y la que elija es una de esas elecciones de "estilo de vida" que todos tenemos que hacer. Creo que hay un buen caso para que DISTINCT sea más explícito (y, por lo tanto, es más considerado para la persona que heredará su código, etc.) pero eso no significa que la construcción GROUP BY sea una opción no válida.
Creo que este ''GRUPO POR es para agregados'' es el énfasis equivocado. La gente debe tener en cuenta que la función de ajuste (MAX, MIN, COUNT, etc.) se puede omitir para que puedan entender la intención del codificador cuando sea.
El optimizador ideal reconocerá construcciones de SQL equivalentes y siempre elegirá el plan ideal en consecuencia. Para el motor SQL de tu vida real de elección, debes probar :)
Tenga en cuenta que la posición de la palabra clave DISTINCT en la cláusula de selección puede producir resultados diferentes, por ejemplo, contraste:
SELECT COUNT(DISTINCT C) FROM myTbl;
SELECT DISTINCT COUNT(C) FROM myTbl;
En Hive (HQL), agrupar puede ser mucho más rápido que distinto, porque el primero no requiere comparar todos los campos en la tabla. Consulte https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct .
En esa consulta particular no hay diferencia. Pero, por supuesto, si agrega columnas agregadas, tendrá que usar agrupar por.
Espero que exista la posibilidad de diferencias sutiles en su ejecución. Verifiqué los planes de ejecución para dos consultas funcionalmente equivalentes en estas líneas en 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 |
---------------------------------------------------------------------------
La operación intermedia es ligeramente diferente: "HASH GROUP BY" vs. "HASH UNIQUE", pero los costos estimados, etc. son idénticos. Luego los ejecuté con el rastreo activado y los recuentos de operaciones reales fueron los mismos para ambos (excepto que el segundo no tuvo que hacer ninguna lectura física debido al almacenamiento en caché).
Pero creo que debido a que los nombres de las operaciones son diferentes, la ejecución seguiría rutas de código algo diferentes y eso abre la posibilidad de diferencias más significativas.
Creo que deberías preferir la sintaxis DISTINCT para este propósito. No es solo un hábito, sino que más claramente indica el propósito de la consulta.
GROUP BY tiene un significado muy específico que es distinto (je) de la función DISTINCT.
GRUPO POR hace que los resultados de la consulta se agrupen utilizando la expresión elegida, luego se pueden aplicar funciones agregadas, que actuarán en cada grupo, en lugar de en el conjunto de resultados completo.
Aquí hay un ejemplo que podría ayudar:
Dada una tabla que se ve así:
name
------
barry
dave
bill
dave
dave
barry
john
Esta consulta:
SELECT name, count(*) AS count FROM table GROUP BY name;
Producirá una salida como esta:
name count
-------------
barry 2
dave 3
bill 1
john 1
Lo que obviamente es muy diferente de usar DISTINCT. Si desea agrupar sus resultados, use GROUP BY, si solo desea una lista única de una columna específica, use DISTINCT. Esto le dará a su base de datos la oportunidad de optimizar la consulta para sus necesidades.
La eficiencia funcional es totalmente diferente. Si desea seleccionar solo el "valor de retorno", excepto el duplicado, usar distintas es mejor que agrupar por. Debido a que "agrupar por" incluye (ordenar y eliminar), "distinto" incluye (eliminar)
La forma en que lo entendí siempre es que usar distintas es lo mismo que agrupar por cada campo que seleccionó en el orden en que las seleccionó.
es decir:
select distinct a, b, c from table;
es lo mismo que:
select a, b, c from table group by a, b, c
La respuesta de MusiGenesis es funcionalmente correcta con respecto a su pregunta como se indica; SQL Server es lo suficientemente inteligente como para darse cuenta de que si está utilizando "Agrupar por" y no está usando ninguna función agregada, entonces lo que realmente quiere decir es "Distinto", y por lo tanto genera un plan de ejecución como si simplemente usara "Distinto . "
Sin embargo, creo que también es importante tener en cuenta la respuesta de Hank , ya que el tratamiento desagradable de "Group By" y "Distinct" podría dar lugar a algunos ataques perniciosos si no tienes cuidado. No es del todo correcto decir que esto no es "una pregunta sobre agregados" porque está preguntando acerca de la diferencia funcional entre dos palabras clave de consulta SQL, una de las cuales está destinada a usarse con agregados y otra no.
Un martillo puede trabajar para atornillar en un tornillo a veces, pero si tiene un destornillador a mano, ¿para qué molestarse?
(... para los fines de esta analogía, Hammer : Screwdriver :: GroupBy : Distinct
y screw => get list of unique values in a table column
)
Leí todos los comentarios anteriores pero no vi a nadie señalar la diferencia principal entre Group By y Distinct aparte del bit de agregación.
Distinct devuelve todas las filas y luego las desduplica, mientras que Group By dededuplica las filas a medida que las lee el algoritmo una por una.
Esto significa que pueden producir diferentes resultados!
Por ejemplo, los siguientes códigos generan diferentes resultados:
SELECT distinct ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable
SELECT ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable
GROUP BY Name
Si hay 10 nombres en la tabla donde 1 de ellos es un duplicado de otro, la primera consulta devuelve 10 filas, mientras que la segunda consulta devuelve 9 filas.
¡La razón es lo que dije arriba para que puedan comportarse de manera diferente!
No hay una diferencia significativa entre el grupo por y la cláusula distinta, excepto el uso de funciones agregadas. Ambos se pueden usar para distinguir los valores, pero si en el punto de vista de rendimiento el grupo es mejor. Cuando se usa una palabra clave distinta, internamente usó una operación de clasificación que se puede ver en el plan de ejecución.
Prueba el ejemplo simple
Declare @tmpresult table (Id tinyint)
Insertar en @tmpresult Select 5 Union all Select 2 Union all Select 3 Union all Select 4
Seleccione una identificación distinta de @tmpresult
Para la consulta que publicaste, son idénticas. Pero para otras consultas que pueden no ser ciertas.
Por ejemplo, no es lo mismo que:
SELECT C FROM myTbl GROUP BY C, D
Por favor, no use GROUP BY cuando quiere decir DISTINCT, incluso si funcionan de la misma manera. Supongo que está intentando eliminar milisegundos de las consultas, y debo señalar que el tiempo del desarrollador es mucho más caro que el tiempo de la computadora.
Sé que es un post viejo. Pero sucede que tuve una consulta que usaba el grupo solo para devolver valores distintos al usar esa consulta en informes de sapo y oráculo todo funcionó bien, me refiero a un buen tiempo de respuesta. Cuando migramos de Oracle 9i a 11g, el tiempo de respuesta en Toad fue excelente, pero en el informe tardamos unos 35 minutos en finalizar el informe. Cuando usamos la versión anterior, demoramos unos 5 minutos.
La solución fue cambiar el grupo y usar DISTINCT y ahora el informe se ejecuta en unos 30 segundos.
Espero que esto sea útil para alguien con la misma situación.
Si está utilizando un GROUP BY sin ninguna función agregada, internamente se tratará como DISTINCT, por lo que en este caso no hay diferencia entre GROUP BY y DISTINCT.
Pero cuando se le proporciona una cláusula DISTINCT, es mejor utilizarla para encontrar sus registros únicos porque el objetivo de GROUP BY es lograr la agregación.
Si usa DISTINCT con varias columnas, el conjunto de resultados no se agrupará como lo hará con GROUP BY, y no puede usar funciones agregadas con DISTINCT.
Solo estás notando eso porque estás seleccionando una sola columna.
Intenta seleccionar dos campos y ver qué pasa.
Group By está destinado para ser utilizado de esta manera:
SELECT name, SUM(transaction) FROM myTbl GROUP BY name
Lo que mostraría la suma de todas las transacciones para cada persona.
Tenía esta pregunta antes, necesito agregar tres columnas de mi tabla de 4 millones de filas (las tres columnas en una nueva columna de una tabla nueva) pero solo las diferentes.
Así que ejecuté mi procedimiento almacenado que contiene esta consulta con el método ''agrupar por'' y tomó 32 minutos. Luego lo ejecuté de nuevo, pero con el método ''distinto'' y me tomó 25 minutos.
Es el mismo resultado, pero fue un poco más rápido con el segundo método
Tienen diferentes semánticas, incluso si tienen resultados equivalentes en sus datos particulares.
Utilice DISTINCT
si solo desea eliminar duplicados. Use GROUPY BY
si desea aplicar operadores agregados ( MAX
, SUM
, GROUP_CONCAT
, ..., o una cláusula HAVING
).
En la perspectiva de Teradata :
Desde el punto de vista del conjunto de resultados, no importa si usa DISTINCT o GROUP BY en Teradata. El conjunto de respuestas será el mismo.
Desde el punto de vista del rendimiento, no es lo mismo.
Para comprender qué afecta al rendimiento, debe saber qué sucede en Teradata al ejecutar una declaración con DISTINCT o GROUP BY.
En el caso de DISTINCT, las filas se redistribuyen inmediatamente sin que tenga lugar ninguna preagregación, mientras que en el caso de GRUPO POR, en un primer paso se realiza una preagregación y solo entonces se redistribuyen los valores únicos a través de los AMP.
No piense ahora que GROUP BY siempre es mejor desde el punto de vista del rendimiento. Cuando tiene muchos valores diferentes, el paso de preagregación de GROUP BY no es muy eficiente. Teradata tiene que ordenar los datos para eliminar los duplicados. En este caso, puede ser mejor en primer lugar la redistribución, es decir, usar la instrucción DISTINCT. Solo si hay muchos valores duplicados, la instrucción GROUP BY es probablemente la mejor opción ya que solo una vez que se lleva a cabo el paso de deduplicación, después de la redistribución.
En resumen, DISTINCT vs. GROUP BY en Teradata significa:
GRUPO POR -> para muchos duplicados DISTINCT -> ninguno o solo algunos duplicados. A veces, cuando usa DISTINCT, se queda sin espacio de spool en un AMP. La razón es que la redistribución tiene lugar de inmediato, y el sesgo podría hacer que los AMP se queden sin espacio.
Si esto sucede, es probable que tenga una mejor oportunidad con GROUP BY, ya que los duplicados ya se eliminaron en un primer paso y se mueven menos datos a través de los AMP.
GROUP BY
permite usar funciones agregadas, como AVG
, MAX
, MIN
, SUM
y COUNT
. Otra mano DISTINCT
simplemente elimina duplicados.
Por ejemplo, si tiene un montón de registros de compra, y quiere saber cuánto gastó cada departamento, podría hacer algo como:
SELECT department, SUM(amount) FROM purchases GROUP BY department
Esto le dará una fila por departamento, que contiene el nombre del departamento y la suma de todos los valores de amount
en todas las filas de ese departamento.
No hay diferencia (en SQL Server, al menos). Ambas consultas utilizan el mismo plan de ejecución.
http://sqlmag.com/database-performance-tuning/distinct-vs-group
Tal vez hay una diferencia, si hay subconsultas involucradas:
No hay diferencia (al estilo de Oracle):
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212