GROUP BY和DISTINCT有什么区别


310

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

SELECT c FROM myTbl GROUP BY C

与以下结果相同:

SELECT DISTINCT C FROM myTbl

我很好奇,SQL引擎处理命令的方式是否有所不同,或者它们确实是同一回事?

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

编辑:这不是有关聚合的问题。GROUP BY已理解with与聚合函数的使用。


11
这不是关于聚合的问题,它是GROUP BY在没有聚合功能存在时的功能与其他功能相同
Brettski

2
您也可以这样做,SELECT c FROM myTbl UNION SELECT c FROM myTbl并获得相同的结果...但是,当SELECT DISTINCT非常简单时,为什么要使事情复杂化。
jarlh

的“逻辑执行顺序” GROUP BY远早于“选择”,并DISTINCT遵循选择。
Used_By_Already

我没有看到的一个非常小的区别是DISTINCT导致实际选择该字段-即该值将出现在结果集中。GROUP BY可以有效地删除重复项,而无需实际选择该字段。在大多数情况下,这是无关紧要的,但在其他情况下可能正是您想要的。如果最终使用GROUP BY代替DISTINCT,则可能需要在代码中提供解释性注释。
rinogo '18年

底线似乎是因为重复删除发生在执行计划中的不同点,所以一个可以比另一个效率更高,因为重复删除需要在该索引上排序或使用该索引。因此,从早期删除重复数据中可能会有一个好处,或者该好处可能来自早期使用不同的索引,然后在剩余的行数很少且排序可以忽略时稍后再进行排序。
bielawski

Answers:


245

就您提出的问题而言,MusiGenesis的回复在功能上是正确的;SQL Server足够聪明,可以意识到,如果您使用的是“分组依据”而不使用任何聚合函数,那么您实际上的意思是“不同的”-因此,它生成的执行计划就像您只是使用“不同的” ”。

但是,我认为也必须注意Hank的响应-如果不小心,对“ Group By”和“ Distinct”的轻描淡写可能会导致一些危险的陷阱。说这不是“关于聚合的问题”是不完全正确的,因为您要询问两个SQL查询关键字之间的功能差异,其中一个SQL关键字旨在与聚合一起使用,而另一个则不能与聚合一起使用

锤子有时可以用螺丝打入,但是如果您有一把螺丝刀,为什么要打扰呢?

(就此类推而言,Hammer : Screwdriver :: GroupBy : Distinctscrew => get list of unique values in a table column


我完全同意您Skeolan。当我遇到此功能时,我感到非常惊讶。这不是我打算使用的东西,而是在我正在工作的这个新地方完成工作的一种方式。
Brettski

至少在Oracle 12中,确实存在DISTINCT,UNION获取不同值和GROUP BY工作不同的情况。今天早些时候,我遇到了一个案例,其中DISTINCT和UNION所引起的oracle错误,但是GROUP BY起作用了。我只从视图中选择1列,没有使用任何聚合;我仍然对为什么需要它感到困惑,但是它确实确认了执行方面的一些差异。正如其他人指出的那样,它也允许您不在select中的GROUP BY列,尽管没有聚合很少会需要。
ZeroK 2015年

1
对于SQL,您总是可以同时使用螺丝刀和锤子。为什么要用锤子拧螺丝?
jarlh

就您的类比而言,要清楚一点-在这种情况下,您的锤子== GroupBy和螺丝刀==是否不同?
HopeKing

哇,这个十岁的问题仍然有腿!如果螺丝是“唯一值列表”,则“螺丝刀”为螺丝刀。我将更新答案以使类推更清楚。
Skeolan '18

136

GROUP BY让您使用聚合函数,如AVGMAXMINSUM,和COUNT。另一方面,DISTINCT只删除重复项。

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

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

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


2
我理解使用GROUP BY,这个问题是基于以下事实:当不存在聚合函数时,它将返回一个不同的数据集。
Brettski

2
因为GROUP BY隐式地对要分组的列的值执行DI​​STINCT(对不起,所以很抱歉)。
乔·皮内达

不能使用DISTINCT+聚合函数吗?像这样:select distinct department, SUM(amount) from ...
Shafizadeh

@Sajad,可以的,但是您仍然必须有GROUP BY,因此DISTINCT不会为您做任何事情。
ZeroK 2015年


40

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

除了不同的是DISTINCTGROUP BY允许在每个组中汇总数据(许多其他答案都提到过)这一事实,我认为最重要的区别是,这两个操作以逻辑顺序SELECT在两个非常不同的步骤“发生” 语句中执行的操作的一部分

这是最重要的操作:

  • FROM(包括JOINAPPLY等)
  • WHERE
  • GROUP BY (可以删除重复项)
  • 集合体
  • HAVING
  • 视窗功能
  • SELECT
  • DISTINCT (可以删除重复项)
  • UNIONINTERSECTEXCEPT (可删除重复)
  • 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

我已经在博客文章中更深入地讨论了这个主题


老实说,我对这个问题没有立即讨论执行顺序感到很惊讶。谢谢,也很好地解释了。关于您的观点2.一些(一个?)数据库确实允许在整个查询中使用选择别名(我知道的是Teradata,但这是一个例外)。
Used_By_Already

@Used_By_Already:当然,某些数据库可以做到这一点。许多数据库仅允许部分使用这些别名(例如,不允许,WHERE但也许GROUP BY)。无论如何,我认为这是个坏主意,出于便携性和维护原因,建议不要使用该功能。“突然”它将不再起作用,例如,当为聚合函数或窗口函数加上别名时。
卢卡斯·埃德

never using that feature for portability and maintenance reasons!! 100%同意...&我现在也喜欢您的博客,很棒的工作。干杯。
Used_By_Already '17

32

使用DISTINCT,如果你只是想删除重复。使用GROUPY BY,如果你想将集合运算符(MAXSUMGROUP_CONCAT,...,或HAVING条款)。


19

我希望它们的执行之间可能存在细微差异。我在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 |
---------------------------------------------------------------------------

中间操作略有不同:“哈希组”与“哈希唯一”,但估计成本等相同。然后,我在跟踪时执行了这些操作,并且两者的实际操作计数是相同的(除了第二个操作由于缓存而不必进行任何物理读取)。

但是我认为,因为操作名称不同,所以执行将遵循略有不同的代码路径,这带来了更大差异的可能性。

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


14

对于您发布的查询,它们是相同的。但是对于其他查询可能并非如此。

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

SELECT C FROM myTbl GROUP BY C, D

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个名称,其中一个与另一个名称重复,则第一个查询返回10行,而第二个查询返回9行。

原因是我上面所说的,所以他们的行为可能会有所不同!


11
这是因为虽然您仅Name在第二个查询中进行分组,但distinct关键字同时适用于列Name和第一个查询ROW_NUMBER()select子句中的列。如果您还按第二个查询中的第一列进行分组,则这些查询将返回相同的结果。

这是的一个结果order of execution的SQL子句其是(在一般意义上) FROM and ON (joins)WHEREGROUP BYHAVINGSELECTDISTINCTORDER BYLIMIT / OFFSET / TOP所以被施加从而导致一行中的第二查询的名称以数按组由减少以及后来的ROW_NUMBER()每个唯一的名称。在第一个查询中,在应用distinct之前先应用row_number(),并且由于row_number()函数的性质,每一行都会获得唯一的整数,因此即使存在重复的名称值,也会返回每一行。
Used_By_Already

12

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


11

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


6

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


6

即使您指的是DISTINCT,也请不要使用GROUP BY,即使它们碰巧也能正常工作。我假设您正在尝试从查询中节省毫秒,并且我必须指出,开发人员的时间比计算机的时间要贵几个数量级。


5

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

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


4

group by用于聚合操作中-例如当您想获得按列C细分的B计数时

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

听起来很独特-您获得了唯一的行。

在sql server 2005中,查询优化器看起来能够优化我运行的简单示例中的差异。但是,如果您能在所有情况下都依靠它,Dunno。



3

从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->用于许多重复DISTINCT->不或仅重复一些。有时,使用DISTINCT时,AMP上的线轴空间用完了。原因是重新分配立即发生,并且歪斜可能导致AMP用完空间。

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


什么Teradata
Brettski

Teradata是一个关系数据库管理系统(RDBMS),能够支持来自各种客户端平台的许多并发用户。Teradata与ANSI标准兼容,并且完全基于并行体系结构构建。
Ram Ghadiyaram

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;

1

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

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

按以下方式使用分组依据:

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

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


这不是聚集的问题。在您的示例中,SELECT c,d FROM mytbl GROUP BY C,D; 实际上将返回与SELECT DISTINCT C,D FROM mytbl相同的数据集;这是问题的基本原理
Brettski

1

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

解决的办法是更改组并使用DISTINCT,现在报告运行大约30秒。

我希望这对处于相同情况的人有用。


1

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

如果要显示没有重复的数据,我总是使用DISTINCT。

如果我想进行诸如求和芒果总量之类的计算,我将使用GROUP BY


0

我一直了解的方式是,使用distinct等同于按照选择顺序对每个选定字段进行分组。

即:

select distinct a, b, c from table;

是相同的:

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

同意,但与通过a,b,c从表组中选择c,b,a相同
Dheer

是的,它是一样的
Caius Jard

0

功能效率完全不同。如果您只想选择“返回值”(重复项除外),则使用distinct优于分组依据。因为“分组依据”包括(排序+删除),所以“不同”包括(删除)



0

有时它们可​​能会为您提供相同的结果,但它们的含义/含义不同。主要区别在于语法。

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


0

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

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

范例:

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

-1

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

尝试简单的例子

声明@tmpresult表(ID tinyint)

插入到@tmpresult中选择5全部合并选择2全部合并选择3全部合并选择4

从@tmpresult选择不同的ID


与众不同,将由两个人组成
vignesh '16
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.