【问题标题】:Is there any difference between GROUP BY and DISTINCTGROUP BY 和 DISTINCT 之间有什么区别吗
【发布时间】:2010-09-14 22:13:55
【问题描述】:

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

SELECT c FROM myTbl GROUP BY C

与以下结果相同:

SELECT DISTINCT C FROM myTbl

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

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

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

【问题讨论】:

  • 这不是关于聚合的问题,它是一个 GROUP BY,当不存在聚合函数时,其功能与 distinct
  • 你也可以通过SELECT c FROM myTbl UNION SELECT c FROM myTbl 得到同样的结果……但是当SELECT DISTINCT 这么简单的时候,为什么要把事情复杂化呢。
  • GROUP BY 的“逻辑执行顺序”远早于“SELECT”,DISTINCT 遵循 select。
  • 我没有看到的一个非常小的区别是DISTINCT 会导致实际选择字段 - 即该值将出现在结果集中。 GROUP BY 可以有效地删除重复项,而无需实际选择字段。在大多数情况下,这有点无关紧要,但可能正是您在其他情况下想要的。如果您最终使用GROUP BY 代替DISTINCT,则可能需要在代码中添加解释性注释。
  • 在 dba 上,问题 mysql-using-distinct-and-group-by-together 也包含有用的回复。

标签: sql group-by distinct


【解决方案1】:

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

但是,我认为注意 Hank 的回应也很重要 - 如果您不小心,对“Group By”和“Distinct”的随意处理可能会导致一些有害的陷阱。说这不是“关于聚合的问题”并不完全正确,因为您要问的是两个 SQL 查询关键字之间的功能差异,其中一个 旨在与聚合一起使用,另一个其中不是。

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

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

【讨论】:

  • 我完全同意你的观点。当我遇到这个功能时,我感到非常惊讶。这不是我打算使用的东西,而是我工作的这个新地方的一种方式。
  • 至少在 Oracle 12 中似乎确实存在 DISTINCT、通过 UNION 获取不同值和 GROUP BY 工作方式不同的情况。我今天早些时候刚遇到一个案例,其中 DISTINCT 和 distinct by UNION 导致 oracle 错误,但 GROUP BY 有效;我从视图中只选择了 1 列而不使用任何聚合;我仍然对它为什么需要它感到困惑,但它确实证实了执行中存在一些差异。正如其他人指出的那样,它还允许您 GROUP BY 不在选择中的列,尽管在没有聚合的情况下很少需要这样做。
  • 当涉及到 SQL 时,您总是可以同时使用螺丝刀和锤子。为什么要用锤子敲螺丝?
  • 只是为了清楚你的类比 - 在这种情况下你的锤子 == GroupBy 和螺丝刀 == 不同吗?
  • 哇,这个十年前的问题还有腿! “独特”是螺丝刀,如果“唯一值列表”是螺丝。我将更新答案以使类比更清楚。
【解决方案2】:

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

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

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

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

【讨论】:

  • GROUP BY 的使用我理解,这个问题是基于这样一个事实,即当没有聚合函数存在时它返回一个不同的数据集。
  • 因为 GROUP BY 隐式地对您分组的列的值进行了 DISTINCT (对不起,杂音)。
  • 不能使用DISTINCT + 聚合函数吗?像这样:select distinct department, SUM(amount) from ...
  • @Sajad,您可以这样做,但您仍然必须拥有 GROUP BY,因此 DISTINCT 不会为您做任何事情。
【解决方案3】:

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

除了与DISTINCT 不同,GROUP BY 允许聚合数据每组(许多其他答案已经提到),我认为最重要的区别是事实这两个操作“发生”在logical order of operations that are executed in a SELECT statement 中的两个非常不同的步骤。

以下是最重要的操作:

  • FROM(包括JOINAPPLY等)
  • 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 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

该查询是“错误的”,并产生如下内容:

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

旁注: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 的一个缺点是有时过于冗长。出于与我们之前看到的相同的原因(即操作的逻辑顺序),我们不能“轻松”按我们正在投影的东西进行分组。

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

【讨论】:

  • 我很惊讶地发现执行顺序没有立即讨论这个问题。谢谢,也解释的很好。关于你的观点 2。一些(一个?)数据库确实允许在整个查询中使用选择别名(我知道的是 Teradata,但它是一个例外)。
  • @Used_By_Already:当然,有些数据库会这样做。许多数据库只允许在部分中使用这些别名(例如,不是WHERE,但可能是GROUP BY)。无论如何,我认为这是一个坏主意,并且出于可移植性和维护的原因,我建议永远不要使用该功能。 “突然”它不再起作用了,例如给聚合函数或窗口函数起别名时。
  • never using that feature for portability and maintenance reasons !! 100% 同意……我现在也喜欢你的博客,干得好。干杯。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      我预计它们的执行可能存在细微差别。 我在 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 语法。这不仅仅是习惯,它更清楚地表明了查询的目的。

      【讨论】:

        【解决方案7】:

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

        例如,不等于:

        SELECT C FROM myTbl GROUP BY C, D
        

        【讨论】:

          【解决方案8】:

          我阅读了上述所有 cmets,但没有看到任何人指出 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 行。

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

          【讨论】:

          • 这是因为虽然您在第二个查询中仅按 Name 分组,但 distinct 关键字适用于 Name 列和 select 子句中的 ROW_NUMBER() 列的第一个查询。如果您还在第二个查询中按第一列分组,则查询将返回相同的结果。
          • 这是 SQL 子句的 order of execution 的结果,即(一般意义上)FROM and ON (joins)WHEREGROUP BYHAVINGSELECT、@ 987654333@ , ORDER BYLIMIT / OFFSET / TOP 所以第二个查询名称的数量按组减少,然后应用 row_number() 导致每个唯一名称一行。在第一个查询中, row_number() 在应用 distinct 之前应用,并且由于 row_number() 函数的性质,每一行都有一个唯一的整数,因此即使存在重复的名称值,也会返回每一行。
          【解决方案9】:

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

          【讨论】:

            【解决方案10】:

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

            【讨论】:

            • 这是一个怎样的答案?简单地说这是语义上的差异,不会增加任何信息。
            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

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

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

              【讨论】:

                【解决方案13】:

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

                【讨论】:

                  【解决方案14】:

                  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 -> 对于许多重复项 DISTINCT -> 没有或只有几个重复。 有时,在使用 DISTINCT 时,您会用完 AMP 上的假脱机空间。原因是重新分配会立即发生,并且偏差可能会导致 AMP 空间不足。

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

                  【讨论】:

                  • 什么是Teradata
                  • Teradata 是一个关系数据库管理系统 (RDBMS),能够支持来自各种客户端平台的许多并发用户。 Teradata 与 ANSI 标准兼容,并且完全建立在并行架构之上。
                  【解决方案15】:

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

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

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

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

                  【讨论】:

                    【解决方案16】:

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

                    【讨论】:

                      【解决方案17】:

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

                      我认为这个“GROUP BY 用于聚合”是错误的强调。大家应该知道,set函数(MAX、MIN、COUNT等)可以省略,这样才能理解编码者的意图。

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

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

                      SELECT COUNT(DISTINCT C) FROM myTbl;
                      
                      SELECT DISTINCT COUNT(C) FROM myTbl;
                      

                      【讨论】:

                        【解决方案18】:

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

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

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

                        【讨论】:

                          【解决方案19】:

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

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

                          Group By 打算这样使用:

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

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

                          【讨论】:

                          • 这不是聚合的问题。在您的示例中, SELECT c, d FROM mytbl GROUP BY C, D;实际上将返回与 SELECT DISTINCT C, D FROM mytbl 相同的数据集;这是问题的基本原理
                          【解决方案20】:

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

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

                          【讨论】:

                            【解决方案21】:

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

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

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

                            【讨论】:

                              【解决方案22】:

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

                              即:

                              select distinct a, b, c from table;
                              

                              等同于:

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

                              【讨论】:

                              • 同意,但是否和 select c,b,a from table group by a,b,c 一样
                              • 是的,应该是一样的
                              【解决方案23】:

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

                              【讨论】:

                                【解决方案24】:

                                一般我们可以使用DISTINCT来消除表格中特定列的重复项。

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

                                例子:

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

                                【讨论】:

                                  【解决方案25】:

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

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

                                  【讨论】:

                                    【解决方案26】:

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

                                    试试简单的例子

                                    声明@tmpresult 表 ( 身份证小号 )

                                    插入@tmpresult 选择 5 联合所有 选择 2 联合所有 选择 3 联合所有 选择 4

                                    选择不同的 ID 来自@tmpresult

                                    【讨论】:

                                    • 区分和分组都将
                                    猜你喜欢
                                    • 2010-12-15
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2017-12-19
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2013-09-13
                                    相关资源
                                    最近更新 更多