Есть ли разница между GROUP BY и DISTINCT? - PullRequest
272 голосов
/ 03 октября 2008

Я узнал кое-что простое о SQL на днях:

SELECT c FROM myTbl GROUP BY C

Имеет тот же результат, что и:

SELECT DISTINCT C FROM myTbl

Что мне интересно, есть ли что-то другое в том, как механизм SQL обрабатывает команду, или это действительно одно и то же?

Лично я предпочитаю четкий синтаксис, но я уверен, что это скорее привычка, чем все остальное.

РЕДАКТИРОВАТЬ: Это не вопрос о агрегатах. Использование GROUP BY с агрегатными функциями понятно.

Ответы [ 23 ]

212 голосов
/ 03 октября 2008

MusiGenesis 'функционально правильный ответ на ваш вопрос, как указано; SQL Server достаточно умен, чтобы понять, что если вы используете «Группировать по» и не используете никаких агрегатных функций, то на самом деле вы имеете в виду «Отличительный» - и, следовательно, он генерирует план выполнения, как если бы вы просто использовали «Отличительный» . "

Тем не менее, я думаю, что важно отметить ответ Хэнка - более кавалерное обращение с «Group By» и «Distinct» может привести к пагубным последствиям, если вы не будете осторожны , Не совсем правильно говорить, что это «не вопрос об агрегатах», потому что вы спрашиваете о функциональной разнице между двумя ключевыми словами SQL-запроса, одно из которых предназначено для использования с агрегатами , а одно из которого нет.

Иногда молоток может вбивать винт, но если у вас под рукой есть отвертка, зачем?

(для целей этой аналогии Hammer : Screwdriver :: GroupBy : Distinct и screw => get list of unique values in a table column)

127 голосов
/ 03 октября 2008

GROUP BY позволяет использовать агрегатные функции, такие как AVG, MAX, MIN, SUM и COUNT. С другой стороны, DISTINCT просто удаляет дубликаты.

Например, если у вас есть несколько записей о покупках, и вы хотите знать, сколько было потрачено каждым отделом, вы можете сделать что-то вроде:

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

Это даст вам одну строку на отдел, содержащую название отдела и сумму всех значений amount во всех строках для этого отдела.

39 голосов
/ 03 октября 2008

Разницы нет (по крайней мере, в SQL Server). Оба запроса используют один и тот же план выполнения.

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

Может быть, - это разница, если есть подзапросы:

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

Нет никакой разницы (в стиле Oracle):

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

31 голосов
/ 03 октября 2008

Используйте DISTINCT, если вы просто хотите удалить дубликаты. Используйте GROUPY BY, если вы хотите применить агрегатные операторы (MAX, SUM, GROUP_CONCAT, ... или предложение HAVING).

26 голосов
/ 23 августа 2017

В чем отличие от точки зрения простого удаления дубликатов

Помимо того, что в отличие от DISTINCT, GROUP BY допускает агрегирование данных по группе (о чем говорилось во многих других ответах), самым важным отличием, на мой взгляд, является тот факт, что две операции «происходят» на двух очень разных шагах в логическом порядке операций, которые выполняются в операторе SELECT .

Вот наиболее важные операции:

  • FROM (включая JOIN, APPLY и т. Д.)
  • WHERE
  • GROUP BY (можно удалить дубликаты)
  • Скопления
  • HAVING
  • Оконные функции
  • SELECT
  • DISTINCT (можно удалить дубликаты)
  • UNION, INTERSECT, EXCEPT (можно удалить дубликаты)
  • ORDER BY
  • OFFSET
  • LIMIT

Как видите, логический порядок каждой операции влияет на то, что можно сделать с ней, и как она влияет на последующие операции. В частности, тот факт, что операция GROUP BY «происходит раньше» операция SELECT (проекция) означает, что:

  1. Это не зависит от проекции (что может быть преимуществом)
  2. Он не может использовать какие-либо значения из проекции (что может быть недостатком)

1. Это не зависит от проекции

Пример, в котором полезно не зависеть от проекции, - это если вы хотите рассчитать оконные функции по различным значениям:

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

При запуске с базой данных Sakila это дает:

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

То же самое не может быть достигнуто с помощью DISTINCT легко:

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

Этот запрос "неправильный" и выдает что-то вроде:

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

Это не то, что мы хотели. Операция DISTINCT «происходит после» проекции, поэтому мы больше не можем удалять оценки DISTINCT, поскольку оконная функция уже рассчитана и спроецирована. Чтобы использовать DISTINCT, нам нужно вложить эту часть запроса:

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

Примечание: В данном конкретном случае мы также можем использовать DENSE_RANK()

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

2. Он не может использовать какие-либо значения из проекции

Одним из недостатков SQL является его многословность. По той же причине, что мы видели раньше (а именно, логический порядок операций), мы не можем «легко» группировать то, что проецируем.

Это недопустимый SQL:

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

Это верно (повторяет выражение)

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

Это также верно (вложенное выражение)

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

Я написал об этой теме более подробно в блоге

19 голосов
/ 03 октября 2008

Я ожидаю, что есть вероятность незначительных различий в их исполнении. Я проверил планы выполнения для двух функционально эквивалентных запросов по этим направлениям в 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 |
---------------------------------------------------------------------------

Средняя операция немного отличается: «HASH GROUP BY» и «HASH UNIQUE», но предполагаемые затраты и т. Д. Идентичны. Затем я выполнил их с включенной трассировкой, и фактическое число операций было одинаковым для обоих (за исключением того, что второй не должен был выполнять какие-либо физические чтения из-за кэширования).

Но я думаю, что из-за того, что имена операций отличаются, выполнение будет следовать несколько иным путям кода, и это открывает возможность более существенных различий.

Я думаю, вы должны предпочесть синтаксис DISTINCT для этой цели. Это не просто привычка, это более четко указывает на цель запроса.

14 голосов
/ 03 октября 2008

Для отправленного вами запроса они идентичны. Но для других запросов это может быть неверно.

Например, это не то же самое, что:

SELECT C FROM myTbl GROUP BY C, D
13 голосов
/ 17 мая 2012

Я прочитал все вышеприведенные комментарии, но не увидел, чтобы кто-либо указывал на основное различие между Group By и Distinct, кроме бита агрегации.

Distinct возвращает все строки, затем дедуплицирует их, тогда как Group By дедуплицирует строки по мере их чтения алгоритмом по очереди.

Это означает, что они могут давать разные результаты!

Например, приведенные ниже коды дают разные результаты:

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

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

Если в таблице 10 имен, одно из которых является дубликатом другого, то первый запрос возвращает 10 строк, а второй - 9 строк.

Причина в том, что я сказал выше, чтобы они могли вести себя по-разному!

12 голосов
/ 03 октября 2008

Если вы используете DISTINCT с несколькими столбцами, результирующий набор не будет сгруппирован, как с GROUP BY, и вы не сможете использовать агрегатные функции с DISTINCT.

11 голосов
/ 03 октября 2008

Они имеют различную семантику, даже если они оказываются эквивалентными результатами для ваших конкретных данных.

...