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

200

Если у меня есть таблица

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

или

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

?

  • 2
    Вы можете проверить себя так же быстро, как и задать вопрос. Вызывает раздражение то, что почти невозможно построить сценарий, в котором DISTINCT превосходит GROUP BY - что раздражает, потому что, очевидно, это не является целью GROUP BY. Однако GROUP BY может привести к вводящим в заблуждение результатам, что, я думаю, является достаточной причиной, чтобы этого избежать.
  • 0
    Есть еще один дубликат с другим ответом. см. MySql - Отдельно от группы По <<< сказано, что GROUP BY лучше
Показать ещё 1 комментарий
Теги:
database
group-by
distinct

15 ответов

196
Лучший ответ

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

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

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

  • 69
    DISTINCT будет быстрее, только если у вас нет индекса (так как он не сортируется). Когда у вас есть индекс, и он используется, это синонимы.
  • 9
    Определение DISTINCT и GROUP BY отличаются тем, что DISTINCT не должен сортировать выходные данные, а GROUP BY по умолчанию делает. Однако в MySQL даже DISTINCT + ORDER BY может по- прежнему работать быстрее, чем GROUP BY из-за дополнительных подсказок для оптимизатора, как объясняется SquareCog.
Показать ещё 3 комментария
82

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

Если вы этого не сделаете, используйте DISTINCT.

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

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

и ваши профессии отсортированы в порядке DESC.

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

Итак,

SELECT DISTINCT u.profession FROM users u

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

  • 4
    Вы можете добавить ORDER BY NULL в GROUP BY чтобы избежать сортировки.
17

Идём простейшим и самым коротким, если вы можете - DISTINCT, похоже, больше того, что вы ищете, только потому, что он даст вам ТОЧНО ответ, который вам нужен, и только это!

12

Все приведенные выше ответы верны, в случае 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 является ключевым словом в этом виде.

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

  • 3
    Хотя этот вопрос о MySQL следует отметить , что второй запрос будет работать только в MySQL. Почти каждая другая СУБД будет отклонять второй оператор, потому что это недопустимое использование оператора GROUP BY.
  • 0
    Ну, «почти» - это проблематичное определение :-) Было бы гораздо полезнее, если бы вы указали конкретную СУБД, которую вы тестировали, чтобы убедиться, что она генерирует ошибку для этого оператора.
Показать ещё 2 комментария
7

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

поэтому будьте осторожны...:)

5

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

SELECT DISTINCT u.profession FROM users u

равно

SELECT u.profession FROM users u GROUP BY u.profession order by null
5

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

Для сравнения:

  • Опишите выбранное имя продукта из northwind.products
  • описать select productname из группы northwind.products по имени продукта

Второй запрос дополнительно добавляет "Использование filesort" в Экземпляр.

  • 1
    Они одинаковы с точки зрения того, что они получают, а не с точки зрения того, как они получают это. Идеальный оптимизатор будет выполнять их таким же образом, но оптимизатор MySQL не идеален. Исходя из ваших доказательств, может показаться, что DISTINCT будет работать быстрее - O (n) против O (n * log n).
  • 0
    Таким образом, "использование файловой сортировки" по сути плохо?
Показать ещё 2 комментария
2

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

2

(больше функциональной заметки)

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

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

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

1

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

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.
1

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

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

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

1

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

SELECT sql_no_cache opnamegroep_intern FROM telwerkenWHERE opnemergroep IN (7,8,9,10,11,12,13) ​​группа by opnamegroep_intern

635 totaal 0,0944 секунды Weergave van records 0 - 29 (635 totaal, query duurde 0.0484 сек)

SELECT sql_no_cache отличный (opnamegroep_intern) FROM telwerkenГДЕ opnemergroep IN (7,8,9,10,11,12,13) ​​

635 totaal 0,2117 секунд (почти на 100% медленнее) Weergave van records 0 - 29 (635 totaal, query duurde 0.3468 sec)

0

Если проблема позволяет, попробуйте с 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 )

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

0

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

0

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню