GROUP BY和DISTINCT有什么区别吗

前几天我学了一些关于SQL的简单知识:

SELECT c FROM myTbl GROUP BY C

结果与:

SELECT DISTINCT C FROM myTbl

我好奇的是,SQL引擎处理命令的方式有什么不同,还是它们真的是一样的东西?

我个人更喜欢独特的语法,但我相信这更多是出于习惯而不是其他原因。

编辑:这不是一个关于聚合的问题。GROUP BY与聚合函数的使用是可以理解的。

328396 次浏览

它们具有不同的语义,即使它们恰好在特定数据上具有相同的结果。

GROUP BY允许您使用聚合函数,如AVGMAXMINSUMCOUNT。 另一方面,DISTINCT只是删除重复项

例如,如果你有一堆购买记录,你想知道每个部门花了多少钱,你可能会这样做:

SELECT department, SUM(amount) FROM purchases GROUP BY department

这将为每个部门提供一行,包含部门名称和该部门所有行中所有amount值的总和。

如果你只想删除重复项,可以使用DISTINCT。如果想应用聚合运算符(MAXSUMGROUP_CONCAT,…),请使用GROUPY BY。,或HAVING子句)。

对于你发布的查询,它们是相同的。但对于其他查询,这可能不是真的。

例如,它不等同于:

SELECT C FROM myTbl GROUP BY C, D

如果对多个列使用DISTINCT,结果集将不会像使用GROUP BY那样进行分组,并且不能对DISTINCT使用聚合函数。

在这个特定的查询中没有区别。但是,当然,如果您添加任何聚合列,那么就必须使用group by。

group by用于聚合操作——比如当您想要获得按列C分解的b的计数时

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

Distinct就是它听起来的样子——你得到唯一的行。

在sql server 2005中,查询优化器似乎能够优化掉我运行的简单示例中的差异。不过,不知道你是否能在所有情况下都指望它。

你之所以注意到这一点,是因为你只选择了一列。

尝试选择两个字段,看看会发生什么。

Group By的用法如下:

SELECT name, SUM(transaction) FROM myTbl GROUP BY name

这将显示每个人的所有交易的总和。

GROUP BY有一个非常具体的含义,它与distinct函数不同。

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。这将使数据库有机会根据您的需要优化查询。

我认为在执行上可能会有细微的差异。 我检查了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唯一”,但估计成本等是相同的。然后,我在跟踪的情况下执行这些操作,两者的实际操作计数是相同的(除了第二个操作由于缓存而不需要进行任何物理读取)。

但我认为,由于操作名称不同,执行将遵循不同的代码路径,这可能会带来更大的差异。

出于这个目的,我认为您应该更喜欢DISTINCT语法。这不仅仅是习惯,它更清楚地表明了查询的目的。

MusiGenesis'的回答在功能上是正确的,关于你的问题;SQL Server足够聪明,可以意识到如果你使用“Group By”而不使用任何聚合函数,那么你实际上的意思是“Distinct”——因此它会生成一个执行计划,就像你只是使用“Distinct”一样。

然而,我认为重要的是要注意汉克的反应以及-漫不经心的处理“Group By”和“Distinct”可能会导致一些有害的陷阱,如果你不小心的话。说这“不是一个关于聚合的问题”并不完全正确,因为你问的是两个SQL查询关键字之间的功能差异,其中一个是意味着与聚合一起使用,另一个不是。

锤子有时可以用来拧螺丝,但如果你手边有螺丝刀,那又何苦呢?

(为了便于类比,Hammer : Screwdriver :: GroupBy : Distinctscrew => get list of unique values in a table column)

当你指的是DISTINCT时,请不要使用GROUP BY,即使它们的工作方式是一样的。我假设您正在尝试从查询中减少毫秒数,我必须指出,开发人员的时间比计算机的时间要昂贵几个数量级。

我对它的理解是,使用distinct就相当于按照所选字段的顺序对它们进行分组。

即:

select distinct a, b, c from table;

等于:

select a, b, c from table group by a, b, c

从“SQL语言”的角度来看,这两种结构是等价的,你选择哪一种是我们都必须做出的“生活方式”选择之一。我认为DISTINCT更明确(因此对继承你代码的人更体贴)是一个很好的例子,但这并不意味着GROUP BY结构是一个无效的选择。

我认为“GROUP BY是用于聚合的”是错误的重点。人们应该意识到set函数(MAX, MIN, COUNT等)可以省略,这样他们就可以理解编码器的意图。

理想的优化器将识别等效的SQL结构,并始终相应地选择理想的计划。对于现实生活中选择的SQL引擎,您必须测试:)

PS注意DISTINCT关键字在select子句中的位置可能会产生不同的结果,例如对比:

SELECT COUNT(DISTINCT C) FROM myTbl;


SELECT DISTINCT COUNT(C) FROM myTbl;

如果你使用的GROUP BY没有任何聚合函数,那么在内部它将被视为DISTINCT,所以在这种情况下,GROUP BY和DISTINCT之间没有区别。

但是,当提供DISTINCT子句时,最好使用它来查找唯一的记录,因为GROUP BY的目标是实现聚合。

我阅读了上面所有的评论,但除了聚合位之外,没有看到任何人指出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个名字,其中一个是另一个的副本,那么第一个查询返回10行,而第二个查询返回9行。

原因就是我上面说的,这样他们就能表现得不一样!

除了聚合函数的使用外,group by子句和distinct子句之间没有显著差异。 两者都可以用来区分值,但如果在性能的角度组由更好。 当使用distinct关键字时,内部使用排序操作,可在执行计划中查看

试试简单的例子

Declare @tmpresult table
(
Id tinyint
)


Insert into @tmpresult
Select 5
Union all
Select 2
Union all
Select 3
Union all
Select 4




Select distinct
Id
From @tmpresult

我知道这是一个旧帖子。但碰巧的是,我有一个查询,使用组通过只是返回不同的值时,使用该查询在蛤蟆和oracle报告一切都工作得很好,我的意思是一个很好的响应时间。当我们从Oracle 9i迁移到11g时,Toad中的响应时间非常好,但在报告中,完成报告需要35分钟,而使用以前的版本大约需要5分钟。

解决方案是通过使用DISTINCT更改组,现在报告在大约30秒内运行。

我希望这对有同样情况的人有用。

仅仅从重复删除功能的角度来看有什么不同

除了与DISTINCT不同的事实,GROUP BY允许聚合数据每组(这已经被许多其他答案提到),在我看来最重要的区别是这两个操作“发生”在SELECT语句中执行的操作的逻辑顺序中两个非常不同的步骤。

以下是最重要的操作:

  • FROM(包括JOINAPPLY等)
  • WHERE
  • GROUP BY (可以删除重复项)
  • 聚合
  • HAVING
  • 窗口函数
  • SELECT
  • DISTINCT (可以删除重复项)
  • __abc0, __abc1, __abc2 __abc3
  • ORDER BY
  • OFFSET
  • LIMIT

如您所见,每个操作的逻辑顺序影响着可以用它做什么以及它如何影响后续操作。具体来说,GROUP BY操作“之前”SELECT操作(投影)意味着:

  1. 它不依赖于投影(这可能是一个优势)
  2. 它不能使用来自投影的任何值(这可能是一个缺点)

1. 它不依赖于投影

一个不依赖于投影的例子是,如果你想计算不同值的窗口函数:

SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating

当对Sakila数据库运行时,将产生:

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

我在一篇博客文章中更深入地写过这个主题

功能效率完全不同。 如果你想只选择“返回值”,除了重复的一个,使用distinct比group by更好。因为“group by”包含(排序+删除),“distinct”包含(删除)

在Teradata透视图:

从结果集的角度来看,在Teradata中使用DISTINCT或GROUP BY并不重要。答案集是一样的。

从性能的角度来看,这是不一样的。

要了解什么会影响性能,您需要知道在使用DISTINCT或GROUP BY执行语句时Teradata上发生了什么。

在DISTINCT的情况下,行被立即重新分配,而不发生任何预聚合,而在GROUP BY的情况下,第一步完成预聚合,然后才在amp之间重新分配唯一值。

现在不要认为GROUP BY从性能角度来看总是更好。当您有许多不同的值时,GROUP BY的预聚合步骤不是很有效。Teradata必须对数据进行排序以删除重复项。在这种情况下,最好先重新分配,即使用DISTINCT语句。只有当有许多重复值时,GROUP BY语句可能是更好的选择,因为只有在重分发之后才执行重复数据删除步骤。

简而言之,DISTINCT vs. GROUP BY在Teradata中的意思是:

GROUP BY -> for many duplicate DISTINCT ->没有或只有几个重复项。 在使用DISTINCT时,有时会耗尽AMP上的线轴空间。原因是重新分配立即发生,倾斜可能会导致AMP耗尽空间。< / p >

如果发生这种情况,使用GROUP BY可能会有更好的机会,因为在第一步中已经删除了重复项,并且在amp之间移动的数据更少。

在Hive (HQL)中,GROUP BY可以比DISTINCT快得多,因为前者不需要比较表中的所有字段。

看到:https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct

有时它们可能会给你同样的结果,但它们是在不同的意义/情况下使用的。主要的区别在于语法。

请仔细注意下面的例子。DISTINCT用于过滤掉重复的值集。(6, cs, 9.1)和(1,cs, 5.5)是两个不同的集合。所以DISTINCT将显示这两行,而GROUP BY Branch将只显示一组。

 SELECT * FROM student;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    2 | mech   |  6.3 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    1 | cs     |  5.5 |
+------+--------+------+
5 rows in set (0.001 sec)


SELECT DISTINCT * FROM student;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    2 | mech   |  6.3 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    1 | cs     |  5.5 |
+------+--------+------+
5 rows in set (0.001 sec)


SELECT * FROM student GROUP BY Branch;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    2 | mech   |  6.3 |
+------+--------+------+
4 rows in set (0.001 sec)

有时,如果不使用一些额外的子句或条件,GROUP BY子句可以实现的结果无法通过DISTINCT实现。如上述情况。

为了得到与DISTINCT相同的结果,你必须像下面这样在GROUP BY子句中传递所有的列名。看看句法上的区别。在这种情况下,你必须了解所有的列名才能使用GROUP BY子句。

SELECT * FROM student GROUP BY Id, Branch, CGPA;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    1 | cs     |  5.5 |
|    2 | mech   |  6.3 |
|    3 | civil  |  7.2 |
|    4 | eee    |  8.2 |
|    6 | cs     |  9.1 |
+------+--------+------+

此外,我还注意到GROUP BY默认情况下以升序显示结果,而DISTINCT则不会。但我不太确定。这可能是不同的供应商。

来源:https://dbjpanda.me/dbms/languages/sql/sql-syntax-with-examples#group-by

通常,我们可以使用DISTINCT来消除表中特定列上的重复项。

在'GROUP BY'的情况下,我们可以应用聚合函数,如 具体列上的AVGMAXMINSUMCOUNT 列名和它的聚合函数在同一列上产生。

例子:

select  specialColumn,sum(specialColumn) from yourTableName group by specialColumn;

在使用方面,GROUP BY用于对要计算的行进行分组。DISTINCT将不做任何计算。它不会显示重复的行。

如果我想要呈现无重复的数据,我总是使用DISTINCT。

如果我想做计算,比如合计芒果的总数,我会使用GROUP BY