Что быстрее, SELECT DISTINCT или GROUP BY в MySQL? - PullRequest
257 голосов
/ 24 февраля 2009

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

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

Ответы [ 15 ]

236 голосов
/ 24 февраля 2009

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

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

Если сомневаешься, проверь!

98 голосов
/ 27 февраля 2009

Если у вас есть индекс на 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.

17 голосов
/ 24 февраля 2009

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

15 голосов
/ 16 мая 2013

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

НО, если вы выберете более одного столбца в запросе, тогда 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 является таким общим ключевым словом.

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

7 голосов
/ 21 июня 2013

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

SELECT DISTINCT u.profession FROM users u

равно

SELECT u.profession FROM users u GROUP BY u.profession order by null
7 голосов
/ 18 ноября 2011

хорошо различимые могут быть медленнее, чем группа в некоторых случаях в postgres (не знаю о других БД).

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

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 голосов
/ 24 февраля 2009

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

Сравнить:

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

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

3 голосов
/ 11 февраля 2014

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

2 голосов
/ 03 июня 2016

Вот простой подход, который будет печатать 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.
2 голосов
/ 21 мая 2012

(более функциональная нота)

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

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

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

...