Что быстрее: SELECT DISTINCT или GROUP BY в MySQL?

Если у меня есть стол

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

и я хочу получить все уникальные значения поля profession, что было бы быстрее (или рекомендовано):

SELECT DISTINCT u.profession FROM users u

or

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

?


person vava    schedule 24.02.2009    source источник
comment
Вы можете проверить себя так же быстро, как зададите вопрос. Раздражает то, что практически невозможно построить сценарий, в котором DISTINCT превосходит GROUP BY, что раздражает, потому что явно не в этом цель GROUP BY. Однако GROUP BY может давать вводящие в заблуждение результаты, и я думаю, что это достаточная причина для того, чтобы этого избежать.   -  person Strawberry    schedule 12.08.2014
comment
Есть еще один дубликат с другим ответом. см. MySql - Distinct vs Group By ‹** в нем говорится, что GROUP BY лучше   -  person kolunar    schedule 03.06.2016
comment
См. здесь, если вы хотите измерить разницу во времени между DISTINCT и GROUP BY, выполняющими ваш запрос.   -  person kolunar    schedule 07.06.2016


Ответы (15)


По сути, они эквивалентны друг другу (на самом деле это то, как некоторые базы данных реализуют DISTINCT под капотом).

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

Если сомневаетесь, протестируйте!

person SquareCog    schedule 24.02.2009
comment
DISTINCT будет быстрее, только если у вас НЕТ индекса (поскольку он не сортирует). Когда у вас есть индекс и он используется, это синонимы. - person Quassnoi; 27.02.2009
comment
Определение DISTINCT и GROUP BY отличается тем, что DISTINCT не должен сортировать вывод, а GROUP BY по умолчанию. Однако в MySQL даже _5 _ + _ 6_ может по-прежнему быть быстрее, чем GROUP BY из-за дополнительных подсказок для оптимизатора, как объяснил SquareCog. - person rustyx; 25.01.2015
comment
DISTINCT работает намного быстрее с большими объемами данных. - person Pankaj Wanjari; 28.12.2015
comment
Я проверил это и обнаружил, что в индексированном столбце mysql group by примерно в 6 раз медленнее, чем отдельный с довольно сложным запросом. Просто добавив это как точку данных. Около 100к строк. Так что проверьте это и убедитесь сами. - person Lizardx; 22.02.2016
comment
см. MySql - Distinct vs Group By ‹** в нем говорится, что GROUP BY лучше - person kolunar; 03.06.2016

Если у вас есть указатель на profession, эти два слова являются синонимами.

Если нет, то используйте DISTINCT.

GROUP BY в MySQL сортирует результаты. Вы даже можете:

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

и отсортируйте свои профессии в DESC порядке.

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

So

SELECT DISTINCT u.profession FROM users u

будет быстрее, если у вас нет индекса на profession.

person Quassnoi    schedule 27.02.2009
comment
Вы можете добавить ORDER BY NULL к GROUP BY, чтобы избежать сортировки. - person Ariel; 20.08.2014
comment
Все еще медленнее даже с группировкой по нулю - person Thanh Trung; 07.06.2019
comment
@ThanhTrung: что медленнее, чем что? - person Quassnoi; 07.06.2019
comment
@Quassnoi groupby медленнее, чем отличное, даже если избегать сортировки - person Thanh Trung; 07.06.2019
comment
Примечание. Квалификаторы заказа для GROUP BY устарели в MySQL 8. - person Matthew Lenz; 27.02.2020

Все приведенные выше ответы верны для случая DISTINCT в одном столбце и GROUP BY в одном столбце. Каждый движок db имеет свою собственную реализацию и оптимизацию, и если вы заботитесь об очень небольшой разнице (в большинстве случаев), вам нужно протестировать на конкретном сервере И конкретной версии! Поскольку реализации могут измениться ...

НО, если вы выберете более одного столбца в запросе, то DISTINCT существенно отличается! Потому что в этом случае он будет сравнивать ВСЕ столбцы всех строк, а не только один столбец.

Итак, если у вас есть что-то вроде:

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

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

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

person daniel.gindi    schedule 16.05.2013
comment
Хотя этот вопрос касается MySQL, следует отметить, что второй запрос будет работать только в MySQL. Почти все остальные СУБД отклонят второй оператор, потому что он неверно использует оператор GROUP BY. - person a_horse_with_no_name; 15.09.2013
comment
Что ж, это почти проблемное определение :-) Было бы гораздо полезнее, если бы вы указали конкретную СУБД, которую вы протестировали, чтобы увидеть, что она генерирует ошибку для этого оператора. - person daniel.gindi; 15.09.2013
comment
Postgres, Oracle, Firebird, DB2, SQL Server для начинающих. MySQL: sqlfiddle.com/#!2/6897c/1 Postgres: sqlfiddle.com / #! 12 / 6897c / 1 Oracle: sqlfiddle.com / #! 12 / 6897c / 1 SQL-сервер: sqlfiddle.com / #! 6 / 6897c / 1 - person a_horse_with_no_name; 15.09.2013
comment
И чтобы сбить нас с толку :), mysql позволяет использовать select distinct(a), b, что означает select distinct a, b, что означает различие в паре. - person Marinos An; 04.03.2021

По возможности выбирайте самый простой и самый короткий - DISTINCT, кажется, больше то, что вы ищете, только потому, что он даст вам ТОЧНО ответ, который вам нужен, и только он!

person Tim    schedule 24.02.2009

В некоторых случаях в postgres может быть медленнее, чем group by, в некоторых случаях (не знаю о других dbs).

проверенный пример:

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

так что будь осторожен ... :)

person OptilabWorker    schedule 18.11.2011
comment
GROUP BY также быстрее, чем DISTINCT в AWS Redshift, потому что GROUP BY использует XN HashAggregate, а DISTINCT использует XN Unique. Это та же проблема, что и в старых версиях Postgres. - person Bernardo Loureiro; 01.07.2020

Group by дороже, чем Distinct, поскольку Group by выполняет сортировку по результату, в то время как unique избегает этого. Но если вы хотите, чтобы group by давал тот же результат, что и отдельный, укажите order by null ..

SELECT DISTINCT u.profession FROM users u

равно

SELECT u.profession FROM users u GROUP BY u.profession order by null
person Ranjith    schedule 21.06.2013
comment
равно SELECT profession FROM users GROUP BY profession - person ; 16.12.2019

Похоже, что запросы не совсем совпадают. По крайней мере, для MySQL.

Сравнивать:

  1. описать выберите отличное название продукта от northwind.products
  2. описать выберите название продукта из группы northwind.products по названию продукта

Второй запрос дополнительно дает "Использование файловой сортировки" в Extra.

person amartynov    schedule 24.02.2009
comment
Они одинаковы с точки зрения того, что они получают, а не с точки зрения того, как они это получают. Идеальный оптимизатор выполнял бы их таким же образом, но оптимизатор MySQL не идеален. Основываясь на ваших доказательствах, может показаться, что DISTINCT будет работать быстрее - O (n) vs O (n * log n). - person SquareCog; 24.02.2009
comment
Значит, использование файловой сортировки - это плохо? - person vava; 25.02.2009
comment
В этом случае это так, потому что вам не нужно сортировать (вы бы сделали, если бы вам понадобились группы). MySQL выполняет сортировку, чтобы разместить одни и те же записи вместе, а затем получить группы путем сканирования отсортированного файла. Вам просто нужны различия, поэтому вам просто нужно хешировать свои ключи при сканировании одной таблицы. - person SquareCog; 25.02.2009
comment
Добавьте ORDER BY NULL к версии GROUP BY, и они будут такими же. - person Ariel; 20.08.2014

В MySQL "Group By" использует дополнительный шаг: filesort. Я понимаю, что DISTINCT быстрее, чем GROUP BY, и это было неожиданностью.

person Carlos    schedule 11.02.2014

После тяжелого тестирования мы пришли к выводу, что GROUP BY быстрее

ВЫБЕРИТЕ sql_no_cache opnamegroep_intern FROM telwerken WHERE opnemergroep IN (7,8,9,10,11,12,13) ​​group by opnamegroep_intern

635 в сумме 0,0944 секунды Записи фургона Weergave от 0 до 29 (всего 635, запрос за 0,0484 секунды)

ВЫБЕРИТЕ sql_no_cache different (opnamegroep_intern) FROM telwerken WHERE opnemergroep IN (7,8,9,10,11,12,13)

Всего 635 0,2117 секунды (почти на 100% медленнее) Записи фургона Weergave от 0 до 29 (всего 635, запрос за 0,3468 секунды)

person Grumpy    schedule 09.06.2015

(больше функционального примечания)

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

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

В таком сценарии DISTINCT u.employer не работает правильно. Возможно, способ есть, но я его просто не знаю. (Если кто-то знает, как сделать такой запрос с помощью DISTINCT, добавьте примечание!)

person Ivan Dossev    schedule 21.05.2012

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

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

ИЛИ попробуйте УСТАНОВИТЬ ВРЕМЯ СТАТИСТИКИ (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;

Он просто отображает количество миллисекунд, необходимых для анализа, компиляции и выполнения каждого оператора, как показано ниже:

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 2 ms.
person kolunar    schedule 03.06.2016

Это не правило

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

В моем проекте иногда я использую group by, а другие - разные.

person user2832991    schedule 16.07.2015

Если вам не нужно выполнять какие-либо групповые функции (сумма, среднее значение и т. Д., Если вы хотите добавить числовые данные в таблицу), используйте SELECT DISTINCT. Я подозреваю, что это быстрее, но мне нечего показать.

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

person tehvan    schedule 24.02.2009

SELECT DISTINCT всегда будет таким же или быстрее, чем GROUP BY. В некоторых системах (например, Oracle) он может быть оптимизирован так, чтобы он был таким же, как DISTINCT для большинства запросов. На других (например, SQL Server) это может быть значительно быстрее.

person Beep beep    schedule 27.02.2009

Если проблема позволяет, попробуйте использовать EXISTS, поскольку он оптимизирован для завершения работы, как только будет найден результат (и не буферизировать ответ), поэтому, если вы просто пытаетесь нормализовать данные для предложение WHERE, подобное этому

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

Более быстрый ответ будет:

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

Это не всегда возможно, но когда доступно, вы увидите более быстрый ответ.

person Daniel R    schedule 09.06.2014