在MySQL中,SELECT DISTINCT或GROUP BY更快吗?


273

如果我有桌子

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可能会产生误导性的结果,我认为有足够的理由避免这种情况。
草莓2014年

还有另一个重复的答案。参见MySql-Distinct vs Group By <<<它说GROUP BY更好
kolunar

如果您要测量DISTINCT和GROUP BY之间的时差,请在此处查看。
kolunar

Answers:


258

它们本质上是彼此等效的(实际上这就是某些数据库DISTINCT在后台实现的方式)。

如果其中之一更快,那就快了DISTINCT。这是因为,尽管两者相同,但是查询优化器将不得不抓住一个事实,即您GROUP BY没有利用任何组成员,而只是利用了他们的键。DISTINCT明确说明这一点,因此您可以使用稍微笨拙的优化程序。

如有疑问,请测试!


76
仅当您没有索引(因为它不排序)时,DISTINCT才会更快。当您有索引并被使用时,它们就是同义词。
Quassnoi

10
的定义DISTINCT,并GROUP BY在差异DISTINCT不具有对输出进行排序,并GROUP BY默认完成。然而,在MySQL连DISTINCT+ ORDER BY可能仍然会比更快GROUP BY由于对优化额外的提示,通过SquareCog解释。
rustyx 2015年

1
使用大量数据,DISTINCT更快。
Pankaj Wanjari 2015年

7
我对此进行了测试,发现在一个索引列mysql上,group by的速度比使用相当复杂的查询的速度慢6倍。只需将其添加为数据点即可。约10万行。因此,对其进行测试,看看自己。
Lizardx '16

参见MySql-Distinct vs Group By <<<它说GROUP BY更好
kolunar

100

如果在上有索引profession,则这两个是同义词。

如果不这样做,请使用DISTINCT

GROUP BYMySQL排序结果。您甚至可以:

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

并按顺序整理您的专业DESC

DISTINCT创建一个临时表并将其用于存储重复项。GROUP BY这样做,但之后对不同的结果进行排序。

所以

SELECT DISTINCT u.profession FROM users u

如果您在上没有索引,则速度会更快profession


6
您可以添加ORDER BY NULLGROUP BY避免排序。
Ariel 2014年

即使按空分组仍然较慢
Thanh Trung

@ThanhTrung:比什么慢?
Quassnoi

@Quassnoi groupby即使避免排序也要比独特慢
Thanh Trung

注:在GROUP BY订单资格在MySQL 8被弃用
马太福音伦兹

18

对于单列上的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是这种方式的常规关键字。

因此,您必须小心,不要在所有情况下都采取正确的答案...您可能会感到困惑,并且得到错误的结果,而您所要做的只是优化!


3
虽然这个问题关于MySQL应该指出的是,第二个查询将工作在MySQL。几乎所有其他DBMS都会拒绝第二条语句,因为这是对GROUP BY运算符的无效使用。
a_horse_with_no_name 2013年

好吧,“几乎”是一个有问题的定义:-)如果您声明已测试的特定DBMS 以查看它会为该语句生成错误,那么它将大有帮助。
daniel.gindi

3
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 Server:sqlfiddle.com/#!6/ 6897c / 1
a_horse_with_no_name13年

17

如果可以的话,请寻求最简单,最短的方法-DISTINCT似乎是您所寻找的更多,这仅仅是因为它可以为您提供所需的确切答案,而且仅此而已!


7

Group by比Distinct昂贵,因为Group by对结果进行排序而独特的避免它。但是,如果要按组进行分组,则结果与按null给出不同的给定顺序相同。

SELECT DISTINCT u.profession FROM users u

等于

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

等于SELECT profession FROM users GROUP BY profession

6

在postgres中,与众不同可能比group by慢一些(不了解其他数据库)。

测试示例:

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

似乎查询并不完全相同。至少对于MySQL。

比较:

  1. 描述从northwind.products中选择不同的产品名称
  2. 按产品名称描述从northwind.products组选择的产品名称

第二个查询在Extra中额外提供了“使用文件排序”。


1
它们在获得的方面是相同的,而不是在获得方式方面是相同的。理想的优化器将以相同的方式执行它们,但是MySQL优化器不是理想的。根据您的证据,DISTINCT的运行速度似乎更快-O(n)vs O(n * log n)。
SquareCog

那么,“使用文件排序”本质上是坏事吗?
vava

在这种情况下是这样,因为您不需要排序(如果需要分组,则需要排序)。MySQL排序是为了将相同的条目放在一起,然后通过扫描排序的文件来获得组。您只需要使用distinct,因此在进行单个表扫描时只需要对键进行哈希处理即可。
SquareCog

1
添加ORDER BY NULLGROUP BY版本中,它们将是相同的。
Ariel 2014年

3

MySQL中,“ Group By”使用了额外的步骤:filesort。我知道DISTINCT它比快GROUP BY,这真是令人惊讶。


3

经过大量测试,我们得出的结论是GROUP BY更快

SELECT SQL_NO_CACHE opnamegroep_intern FROM telwerken WHERE opnemergroepIN(7,8,9,10,11,12,13)由opnamegroep_intern组

635总计0.0944秒Weergave van记录0-29(635总计,查询duurde 0.0484秒)

SELECT sql_no_cache唯一(opnamegroep_intern)FROM telwerken WHERE opnemergroepIN(7,8,9,10,11,12,13)

635个总计0.2117秒(几乎慢了100%)Weergave van记录0-29(635个总计,查询duurde 0.3468秒)


2

(更多功能说明)

在某些情况下,您必须使用GROUP BY,例如,如果您想获得每个雇主的雇员人数:

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

在这种情况下DISTINCT u.employer无法正常工作。也许有办法,但我只是不知道。(如果有人知道如何使用DISTINCT进行此类查询,请添加注释!)


2

这是一种简单的方法,它将为每个查询打印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.

1

这不是规则

对于每个查询....分别尝试不同的内容,然后进行分组...比较完成每个查询的时间并使用速度更快的....

在我的项目中,有时我使用group by和其他


0

如果您不必执行任何组函数(如果要向表中添加数字数据,则可以求和,求平均值等),请使用SELECT DISTINCT。我怀疑它更快,但是我没有什么可展示的。

无论如何,如果您担心速度,请在该列上创建一个索引。


0

SELECT DISTINCT将始终与GROUP BY相同或更快。在某些系统(例如Oracle)上,对于大多数查询,它可能已被优化为与DISTINCT相同。在其他服务器(例如SQL Server)上,它可能要快得多。


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 )

这并非总是可能的,但是如果可用,您将看到更快的响应。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.