396

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

SELECT c FROM myTbl GROUP BY C

与以下结果相同:

SELECT DISTINCT C FROM myTbl

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

我个人更喜欢独特的语法,但我相信它比其他任何东西都更不习惯。

编辑:这不是关于聚合的问题。GROUP BY了解 with 聚合函数的使用。

4

26 回答 26

290

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

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

锤子有时可以用来拧螺丝,但如果你手边有螺丝刀,为什么还要麻烦呢?

(出于类比的目的,Hammer : Screwdriver :: GroupBy : Distinct并且screw => get list of unique values in a table column

于 2008-10-02T20:52:47.033 回答
167

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

例如,如果您有一堆采购记录,并且您想知道每个部门花费了多少,您可能会执行以下操作:

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

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

于 2008-10-02T20:10:58.163 回答
68

从单纯的重复删除功能的角度来看有什么区别

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

以下是最重要的操作:

  • FROM(包括JOIN,APPLY等)
  • WHERE
  • GROUP BY (可以删除重复项)
  • 聚合
  • HAVING
  • 窗口函数
  • SELECT
  • DISTINCT (可以删除重复项)
  • UNION, INTERSECT, EXCEPT (可以删除重复项)
  • 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

我在一篇博文中更深入地讨论了这个主题

于 2017-08-23T07:43:13.443 回答
50

没有区别(至少在 SQL Server 中)。两个查询使用相同的执行计划。

http://sqlmag.com/database-performance-tuning/distinct-vs-group

如果涉及子查询,可能会有所不同:

http://blog.sqlauthority.com/2007/03/29/sql-server-difference-between-distinct-and-group-by-distinct-vs-group-by/

没有区别(Oracle 风格):

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212

于 2008-10-02T20:41:02.973 回答
35

DISTINCT如果您只想删除重复项,请使用。如果GROUPY BY要应用聚合运算符(MAXSUMGROUP_CONCAT、 ... 或HAVING子句),请使用。

于 2008-10-02T20:11:07.973 回答
20

我预计它们的执行可能存在细微差别。我在 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 UNIQUE”,但估计成本等是相同的。然后我在跟踪的情况下执行了这些操作,并且两者的实际操作计数相同(除了第二个由于缓存而不必进行任何物理读取)。

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

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

于 2008-10-02T20:51:01.920 回答
14

对于您发布的查询,它们是相同的。但是对于其他可能不正确的查询。

例如,它与以下内容不同:

SELECT C FROM myTbl GROUP BY C, D
于 2008-10-02T20:11:37.177 回答
14

我阅读了上述所有评论,但除了聚合位之外,没有人指出 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 个名称,其中 1 个与另一个名称重复,则第一个查询返回 10 行,而第二个查询返回 9 行。

原因就是我上面所说的,所以他们可以表现得不同!

于 2012-05-17T16:04:57.037 回答
11

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

于 2008-10-02T20:12:00.280 回答
7

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

于 2008-10-02T20:20:31.277 回答
6

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

于 2008-10-02T20:10:10.707 回答
6

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

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

于 2011-12-28T11:28:58.283 回答
5

当您的意思是 DISTINCT 时,请不要使用 GROUP BY,即使它们碰巧工作相同。我假设您正试图从查询中减少毫秒,我必须指出,开发人员的时间比计算机时间贵几个数量级。

于 2008-10-02T20:57:40.750 回答
5

从 Teradata 的角度来看

从结果集的角度来看,在 Teradata 中使用 DISTINCT 还是 GROUP BY 并不重要。答案集将是相同的。

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

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

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

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

简而言之,Teradata 中的 DISTINCT 与 GROUP BY 意味着:

GROUP BY -> for many duplicates DISTINCT -> no or a few duplicates only 。有时,在使用 DISTINCT 时,您会用完 AMP 上的假脱机空间。原因是重新分配会立即发生,并且偏差可能会导致 AMP 空间不足。

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

于 2018-06-19T00:44:28.000 回答
4

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

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

distinct 听起来像 - 你得到独特的行。

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

于 2008-10-02T20:15:29.867 回答
3

在该特定查询中没有区别。但是,当然,如果您添加任何聚合列,那么您将不得不使用 group by。

于 2008-10-02T20:12:44.397 回答
2

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

我认为这个“GROUP BY 用于聚合”是错误的强调。人们应该知道,设置函数(MAX、MIN、COUNT 等)可以省略,以便他们可以理解编码器的意图。

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

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

SELECT COUNT(DISTINCT C) FROM myTbl;

SELECT DISTINCT COUNT(C) FROM myTbl;
于 2008-10-03T10:09:12.443 回答
2

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

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

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

于 2016-01-29T16:06:26.983 回答
1

您只是注意到这一点,因为您选择的是单个列。

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

Group By 旨在像这样使用:

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

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

于 2008-10-02T20:16:27.383 回答
1

有时它们可​​能会给您相同的结果,但它们旨在用于不同的意义/情况。主要区别在于语法。

请注意下面的示例。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

于 2019-07-17T22:21:41.623 回答
1

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

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

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

于 2019-09-27T09:47:56.207 回答
0

我一直理解的方式是,使用 distinct 与按您选择的每个字段按您选择它们​​的顺序进行分组相同。

IE:

select distinct a, b, c from table;

是相同的:

select a, b, c from table group by a, b, c
于 2008-10-02T21:05:41.370 回答
0

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

于 2018-01-09T04:40:49.070 回答
0

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

请参阅:https ://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct 。

于 2018-07-01T19:08:26.877 回答
0

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

在“GROUP BY”的情况下,我们可以在特定列上应用聚合函数,如 AVGMAXMINSUM和 ,并COUNT在同一列上获取列名及其聚合函数结果。

例子 :

select  specialColumn,sum(specialColumn) from yourTableName group by specialColumn;
于 2019-08-30T15:15:58.107 回答
-1

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

试试简单的例子

声明@tmpresult 表(Id tinyint)

插入 @tmpresult 选择 5 联合全部 选择 2 联合全部 选择 3 联合全部 选择 4

从@tmpresult 中选择不同的 ID

于 2015-02-10T16:56:21.003 回答