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


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

SELECT c FROM myTbl GROUP BY C

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

SELECT DISTINCT C FROM myTbl

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

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

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

24 239

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

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

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

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

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

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

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

  • FROM (включая JOIN,APPLY и т. д.)
  • 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

при запуске против база данных Сакила получается:

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

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

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

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

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

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.

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

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

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

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

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

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

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

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

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

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

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

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

короче говоря, различны и группы в Teradata означает:

группа ПО -> для многих дубликатов 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 минуты. Затем я запустил его снова, но с "отличным" методом, и это заняло 25 минут.

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

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

в 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 ( Id tinyint )

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

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