GROUP BY和DISTINCT之间有什么区别吗?

时间:2008-10-02 20:09:07

标签: sql group-by distinct

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

SELECT c FROM myTbl GROUP BY C

与<:p>具有相同的结果

SELECT DISTINCT C FROM myTbl

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

我个人更喜欢不同的语法,但我确信这更多是出于习惯而不是其他任何事情。

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

26 个答案:

答案 0 :(得分:212)

MusiGenesis'对于您提出的问题,回复在功能上是正确的; SQL Server足够聪明,可以意识到如果你使用“分组依据”并且不使用任何聚合函数,那么你实际上意味着“区别” - 因此它会生成一个执行计划,就像你只是简单地使用“Distinct”一样。“

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

有时锤子可以用螺丝钉驱动,但如果你有方便的螺丝刀,为什么要这么麻烦呢?

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

答案 1 :(得分:126)

GROUP BY可让您使用汇总功能,例如AVGMAXMINSUMCOUNT。 另一方面DISTINCT只删除重复项。

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

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

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

答案 2 :(得分:39)

没有区别(至少在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

答案 3 :(得分:31)

如果您只想删除重复项,请使用DISTINCT。如果您要应用汇总运算符(GROUPY BYMAXSUM,...或GROUP_CONCAT子句,请使用HAVING

答案 4 :(得分:26)

与仅仅重复删除功能的观点

的区别是什么

除了DISTINCT之外,GROUP BY允许聚合每组的数据(许多其他答案都提到过),这是我最重要的区别意见是这两个行动发生的事实&#34;在logical order of operations that are executed in a SELECT statement中的两个截然不同的步骤。

以下是最重要的操作:

  • FROM(包括JOINAPPLY等)
  • WHERE
  • GROUP BY (可删除重复项)
  • 聚合
  • HAVING
  • 窗口功能
  • SELECT
  • DISTINCT (可删除重复项)
  • UNIONINTERSECTEXCEPT (可删除重复项)
  • ORDER BY
  • OFFSET
  • LIMIT

正如您所看到的,每个操作的逻辑顺序都会影响它可以做什么以及它如何影响后续操作。特别是,GROUP BY操作&#34;发生在&#34; SELECT操作(投影)之前的事实意味着:

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

    如果您想在不同的值上计算窗口函数,那么不依赖于投影的示例很有用:

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

    当针对Sakila database运行时,会产生:

    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
    

    该查询是&#34;错误&#34;产生类似的东西:

    rating   rn
    ------------
    G        1
    G        2
    G        3
    ...
    G        178
    NC-17    179
    NC-17    180
    ...
    

    这不是我们想要的。 DISTINCT操作&#34;在&#34; 投影后发生,因此我们无法再删除DISTINCT评级,因为已经计算并预测了窗口函数。为了使用DISTINCT,我们必须嵌套查询的那一部分:

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

    旁注:In this particular case, we could also use DENSE_RANK()

    SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
    FROM film
    

    2。它不能使用投影中的任何值

    SQL的一个缺点是它的冗长有时。出于与我们之前看到的相同的原因(即操作的逻辑顺序),我们不能轻易地&#34;通过我们正在投射的东西进行分组。

    这是无效的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
    

    I've written about this topic more in depth in a blog post

答案 5 :(得分: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 |
---------------------------------------------------------------------------

中间操作略有不同:“HASH GROUP BY”与“HASH UNIQUE”,但估计成本等相同。然后我通过跟踪来执行这些操作,并且实际操作计数对于两者都是相同的(除了第二个因为缓存而不必进行任何物理读取)。

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

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

答案 6 :(得分:14)

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

例如,它与:

不同
SELECT C FROM myTbl GROUP BY C, D

答案 7 :(得分:13)

我阅读了上述所有评论,但没有看到任何人指出除了聚合位之外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行。

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

答案 8 :(得分:11)

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

答案 9 :(得分:11)

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

答案 10 :(得分:5)

GROUP BY具有非常特殊的含义,与DISTINCT函数不同(heh)。

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

答案 11 :(得分:5)

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

答案 12 :(得分:5)

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

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

答案 13 :(得分:4)

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

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

与众不同之处在于它 - 您获得了独特的行。

在sql server 2005中,看起来查询优化器能够优化我运行的简单示例中的差异。不过,如果你能在所有情况下都依赖它,那就不知道了。

答案 14 :(得分:3)

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

答案 15 :(得分:2)

In Teradata perspective

从结果集的角度来看,如果在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 - &gt;对于许多重复 DISTINCT - &gt;没有或只有一些重复。 有时,使用DISTINCT时,AMP上的假脱机空间不足。原因是重新分配立即发生,并且倾斜可能导致AMP耗尽空间。

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

答案 16 :(得分:2)

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

我认为'GROUP BY是聚合'是错误的重点。 Folk应该知道可以省略set函数(MAX,MIN,COUNT等),以便他们能够理解编码器的意图。

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

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

SELECT COUNT(DISTINCT C) FROM myTbl;

SELECT DISTINCT COUNT(C) FROM myTbl;

答案 17 :(得分:1)

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

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

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

答案 18 :(得分:1)

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

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

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

答案 19 :(得分:1)

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

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

Group By旨在像这样使用:

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

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

答案 20 :(得分:0)

功能效率完全不同。 如果您只想选择&#34;返回值&#34;除了重复一个,使用distinct比group by更好。因为&#34; group by&#34;包括(排序+删除),&#34; distinct&#34;包括(删除)

答案 21 :(得分:0)

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

即:

select distinct a, b, c from table;

与:

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

答案 22 :(得分:0)

在Hive(HQL)中,group by可以比非常规更快,因为前者不需要比较表中的所有字段。参见https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct

答案 23 :(得分: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

答案 24 :(得分:0)

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

  

在“ GROUP BY”的情况下,我们可以应用诸如   特定列和提取上的AVGMAXMINSUMCOUNT   列名称及其聚合函数将在同一列上显示。   

示例:

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

答案 25 :(得分:-1)

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

尝试简单的例子

声明@tmpresult表 (   Id tinyint )

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

选择不同 ID 来自@tmpresult