Есть ли разница между GROUP BY и DISTINCT

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

SELECT c FROM myTbl GROUP BY C

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

SELECT DISTINCT C FROM myTbl

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

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

EDIT: это не вопрос о агрегатах. Использование GROUP BY с суммарным функции понятны.

24 ответов


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

однако, я думаю, что важно отметить Хэнк'S, Как хорошо бесцеремонное обращение "группы" и "Отличие" может привести к некоторым пагубным Гоча вниз по линии, если вы не будете осторожны. Не совсем правильно говорить, что это "не вопрос о агрегатах", потому что вы спрашиваете о функциональной разнице между двумя ключевыми словами SQL-запроса, одним из которых является предназначен для использования с агрегатами и один из которых не является.

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

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


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

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

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

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


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

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

может быть is разница, если есть подзапросы:

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

нет разница (Oracle-style):

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


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


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

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

вот самые важные операции:

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

как вы можете видеть, логический порядок каждой операции влияет на то, что с ней можно сделать и как она влияет на последующие операции. В частности, тот факт, что GROUP BY операция "происходит перед" the 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
...

это не то, что мы хотели. The 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

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


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

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

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


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

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

SELECT C FROM myTbl GROUP BY C, D

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


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


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

Distinct возвращает все строки, затем де-дублирует их, тогда как Group By de-deduplicate строки, как они читаются алгоритмом один за другим.

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

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

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 имен в таблице, где 1 из которых является дубликатом другого, первый запрос возвращает 10 строк, тогда как второй запрос возвращает 9 строк.

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


GROUP BY имеет очень специфическое значение, которое отличается (heh) от отдельной функции.

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

вот пример, который может помочь:

учитывая таблицу, которая выглядит так:

name
------
barry
dave
bill
dave
dave
barry
john

запрос:

SELECT name, count(*) AS count FROM table GROUP BY name;

будет результат это:

name    count
-------------
barry   2
dave    3
bill    1
john    1

что, очевидно, очень отличается от использования DISTINCT. Если вы хотите сгруппировать результаты, используйте GROUP BY, если вам нужен уникальный список определенного столбца, используйте DISTINCT. Это даст вашей базе данных возможность оптимизировать запрос для ваших нужд.


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

но когда вам предоставляется предложение DISTINCT, лучше использовать его для поиска ваших уникальных записей, потому что цель GROUP BY-достичь агрегации.


group by используется в агрегатных операциях - например, когда вы хотите получить количество Bs с разбивкой по столбцу c

select C, count(B) from myTbl group by C

distinct-это то, как это звучит-вы получаете уникальные строки.

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


пожалуйста, не используйте GROUP BY, когда вы имеете в виду разные, даже если они работают одинаково. Я предполагаю, что вы пытаетесь сбрить миллисекунды от запросов, и я должен указать, что время разработчика на порядок дороже, чем компьютерное время.


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


С точки зрения "SQL the language" две конструкции эквивалентны, и какой из них вы выбираете, является одним из тех вариантов "образа жизни", которые мы все должны сделать. Я думаю, что есть хороший случай для того, чтобы DISTINCT был более явным (и, следовательно, более внимательным к человеку, который унаследует ваш код и т. д.), Но это не означает, что GROUP BY construct является недопустимым выбором.

Я думаю, что эта "группа ПО для агрегатов" является неправильным акцентом. Люди должны знать, что набор функция (MAX, MIN, COUNT и т. д.) Может быть опущена, чтобы они могли понять намерение кодера, когда оно есть.

идеальный оптимизатор распознает эквивалентные конструкции SQL и всегда будет выбирать идеальный план соответственно. Для вашей реальной жизни SQL engine выбора, вы должны проверить:)

PS обратите внимание, что положение ключевого слова DISTINCT в предложении select может привести к различным результатам, например contrast:

SELECT COUNT(DISTINCT C) FROM myTbl;

SELECT DISTINCT COUNT(C) FROM myTbl;

в перспективе Teradata :

с точки зрения результирующего набора не имеет значения, используете ли вы DISTINCT или GROUP BY в Teradata. Набор ответов будет таким же.

с точки зрения производительности, это не то же самое.

чтобы понять, что влияет на производительность, вам нужно знать, что происходит на Teradata при выполнении оператора с DISTINCT или GROUP BY.

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

Не думайте теперь, что GROUP BY всегда лучше с точки зрения производительности. Когда у вас много разных значений, шаг предварительной Конгрегации GROUP BY не очень эффективен. Teradata должна сортировать данные для удаления дубликатов. В этом случае, возможно, лучше сначала перераспределить, т. е. используйте оператор DISTINCT. Только если существует много повторяющихся значений, оператор GROUP BY, вероятно, является лучшим выбором, так как только шаг дедупликации происходит после перераспределения.

короче говоря, DISTINCT vs. GROUP BY в Teradata означает:

GROUP BY - > для многих дубликатов DISTINCT - > нет или только несколько дубликатов . Иногда, при использовании DISTINCT, у вас заканчивается пространство катушки на усилителе. Причина в том, что перераспределение происходит немедленно, и перекос может привести к тому, что усилители закончатся.

Если это произойдет, у вас, вероятно, больше шансов с GROUP BY, поскольку дубликаты уже удалены на первом шаге, и меньше данных перемещается через усилители.


вы замечаете это только потому, что вы выбираете один столбец.

попробуйте выбрать два поля и посмотреть, что произойдет.

Group By предназначен для использования следующим образом:

SELECT name, SUM(transaction) FROM myTbl GROUP BY name

который покажет сумму всех транзакций для каждого человека.


Я знаю, что это старый пост. Но бывает, что у меня был запрос, который использовал group by только для возврата различных значений при использовании этого запроса в отчетах toad и oracle, все работало нормально, я имею в виду хорошее время ответа. Когда мы мигрировали с Oracle 9i на 11g, время ответа в Toad было отличным, но в reporte потребовалось около 35 минут, чтобы закончить отчет при использовании предыдущей версии потребовалось около 5 минут.

решение состояло в том, чтобы изменить группу и использовать DISTINCT и теперь отчет запускается примерно через 30 секунд.

Я надеюсь, что это полезно для кого-то такая же ситуация.


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

Я.е:

select distinct a, b, c from table;

- это то же, что:

select a, b, c from table group by a, b, c

У меня был этот вопрос раньше, мне нужно добавить три столбца из моей таблицы 4 миллионов строк (три столбца в один новый столбец новой таблицы), но только разные.

поэтому я запустил свою хранимую процедуру, которая содержит этот запрос с помощью метода "group by", и это заняло 32 минуты. Затем я снова запустил его, но с помощью метода "distinct", и это заняло 25 минут.

Это тот же результат, но он был немного быстрее со 2-м методом


эффективность функционируют абсолютно разные. Если вы хотите выбрать только "возвращаемое значение", кроме повторяющегося, используйте distinct лучше, чем group by. Поскольку" group by " включает (сортировка + удаление)," distinct " включает ( удаление)


в Hive (HQL) group by может быть быстрее, чем distinct, потому что первый не требует сравнения всех полей в таблице. Смотри https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct.


нет существенной разницы между предложением group by и distinct, кроме использования агрегатных функций. Оба могут использоваться для различения значений, но если в производительности точка зрения group by лучше. Когда используется ключевое слово distinct, внутри него используется операция сортировки, которую можно просмотреть в плане выполнения.

попробуйте простой пример

объявить таблицу @tmpresult ( Идентификатор тип tinyint )

вставить в @tmpresult Выберите 5 Весь Союз Выберите 2 Союз все Выберите 3 Весь Союз Выберите 4

выберите distinct Идентификатор От @tmpresult