【问题标题】:What's faster, SELECT DISTINCT or GROUP BY in MySQL?MySQL 中的 SELECT DISTINCT 或 GROUP BY 哪个更快?
【发布时间】:2010-10-09 13:16:05
【问题描述】:

如果我有一张桌子

CREATE TABLE users (
  id int(10) unsigned NOT NULL auto_increment,
  name varchar(255) NOT NULL,
  profession varchar(255) NOT NULL,
  employer varchar(255) NOT NULL,
  PRIMARY KEY  (id)
)

我想获取profession 字段的所有唯一值,什么会更快(或推荐):

SELECT DISTINCT u.profession FROM users u

SELECT u.profession FROM users u GROUP BY u.profession

?

【问题讨论】:

  • 您可以在提出问题后尽快进行测试。令人恼火的是,几乎不可能构建一个 DISTINCT 优于 GROUP BY 的场景——这很烦人,因为这显然不是 GROUP BY 的目的。但是,GROUP BY 可能会产生误导性结果,我认为这是避免它的充分理由。
  • 还有另一个答案不同的副本。见MySql - Distinct vs Group By
  • 如果您想通过运行查询来测量 DISTINCT 和 GROUP BY 之间的时间差,请参阅here

标签: mysql sql database group-by distinct


【解决方案1】:

在 mySQL 中,我发现 GROUP BY 会将 NULL 视为不同的,而 DISTINCT 不会。
采用完全相同的 DISTINCT 查询,删除 DISTINCT,并将所选字段添加为 GROUP BY,由于其中一个字段为 NULL,我得到了更多行。

所以.. 我倾向于相信 mySQL 中的 DISTINCT 有更多内容。

【讨论】:

    【解决方案2】:

    这是一个简单的方法,它将为每个查询打印 2 个不同的经过时间。

    DECLARE @t1 DATETIME;
    DECLARE @t2 DATETIME;
    
    SET @t1 = GETDATE();
    SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
    SET @t2 = GETDATE();
    PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);
    
    SET @t1 = GETDATE();
    SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
    SET @t2 = GETDATE();
    PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);
    

    或者试试SET STATISTICS TIME (Transact-SQL)

    SET STATISTICS TIME ON;
    SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
    SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
    SET STATISTICS TIME OFF;
    

    它只是显示解析、编译和执行每条语句所需的毫秒数,如下所示:

     SQL Server Execution Times:
       CPU time = 0 ms,  elapsed time = 2 ms.
    

    【讨论】:

      【解决方案3】:

      这不是规则

      对于每个查询 .... 分别尝试 distinct 然后 group by ... 比较完成每个查询的时间并使用更快的 ....

      在我的项目中,有时我会使用 group by 和 other distinct

      【讨论】:

        【解决方案4】:

        经过大量测试,我们得出的结论是 GROUP BY 更快

        选择 sql_no_cache opnamegroep_intern 来自telwerken WHERE opnemergroep IN (7,8,9,10,11,12,13)​​ group by opnamegroep_intern

        635 总共 0.0944 秒 Weergave van 记录 0 - 29(共 635 条,查询 duurde 0.0484 秒)

        选择 sql_no_cache 不同的(opnamegroep_intern) 来自telwerken WHERE opnemergroep IN (7,8,9,10,11,12,13)​​

        635 总共 0.2117 秒(几乎慢了 100%) Weergave van 记录 0 - 29(共 635 条,查询 duurde 0.3468 秒)

        【讨论】:

          【解决方案5】:

          它们本质上是等价的(实际上这就是一些数据库在底层实现DISTINCT 的方式)。

          如果其中一个更快,它将是DISTINCT。这是因为,尽管两者是相同的,但查询优化器必须抓住这样一个事实,即您的 GROUP BY 没有利用任何组成员,而只是利用他们的键。 DISTINCT 明确说明了这一点,因此您可以使用稍微笨拙的优化器。

          如有疑问,请测试!

          【讨论】:

          • DISTINCT 只有在你没有索引时才会更快(因为它没有排序)。当你确实有一个索引并且它被使用时,它们就是同义词。
          • DISTINCTGROUP BY 的定义不同之处在于DISTINCT 不必对输出进行排序,而GROUP BY 默认情况下会这样做。然而,在 MySQL 中,即使是 DISTINCT+ORDER BY 也可能仍然GROUP BY 快,因为 SquareCog 解释了优化器的额外提示。
          • DISTINCT 在处理大量数据时要快得多。
          • 我对此进行了测试,发现在索引列 mysql 上,group by 比 distinct 执行相当复杂的查询慢约 6 倍。只需将其添加为数据点。大约 100k 行。所以测试一下,自己看看。
          【解决方案6】:

          如果问题允许,请尝试使用 EXISTS,因为它已优化为在找到结果后立即结束(并且不缓冲任何响应),因此,如果您只是尝试像这样对 WHERE 子句的数据进行规范化

          SELECT FROM SOMETHING S WHERE S.ID IN ( SELECT DISTINCT DCR.SOMETHING_ID FROM DIFF_CARDINALITY_RELATIONSHIP DCR ) -- to keep same cardinality
          

          更快的响应是:

          SELECT FROM SOMETHING S WHERE EXISTS ( SELECT 1 FROM DIFF_CARDINALITY_RELATIONSHIP DCR WHERE DCR.SOMETHING_ID = S.ID )
          

          这并不总是可行的,但如果可用,您会看到更快的响应。

          【讨论】:

            【解决方案7】:

            MySQL 中,“Group By”使用了一个额外的步骤:filesort。我意识到DISTINCTGROUP BY 快​​,这真是一个惊喜。

            【讨论】:

              【解决方案8】:

              在 postgres 中的某些情况下,well distinct 可能比 group by 慢(不知道其他数据库)。

              测试示例:

              postgres=# select count(*) from (select distinct i from g) a;
              
              count 
              
              10001
              (1 row)
              
              Time: 1563,109 ms
              
              postgres=# select count(*) from (select i from g group by i) a;
              
              count
              10001
              (1 row)
              
              Time: 594,481 ms
              

              http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I

              所以要小心... :)

              【讨论】:

              • GROUP BY 在 AWS Redshift 中也比 DISTINCT 快,因为 GROUP BY 使用 XN HashAggregate 而 DISTINCT 使用 XN Unique。旧版本的 Postgres 也存在同样的问题。
              【解决方案9】:

              Group by 比 Distinct 昂贵,因为 Group by 对结果进行排序,而 distinct 避免了它。但是,如果你想让 group by 产生与 distinct 相同的结果,请 order by null ..

              SELECT DISTINCT u.profession FROM users u
              

              等于

              SELECT u.profession FROM users u GROUP BY u.profession order by null
              

              【讨论】:

              • 等于SELECT profession FROM users GROUP BY profession
              【解决方案10】:

              对于单列上的 DISTINCT 与单列上的 GROUP BY 的情况,以上所有答案都是正确的。 每个数据库引擎都有自己的实现和优化,如果您关心非常小的差异(在大多数情况下),那么您必须针对特定服务器和特定版本进行测试!由于实施可能会发生变化...

              但是,如果您在查询中选择多个列,则 DISTINCT 本质上是不同的!因为在这种情况下,它将比较所有行的所有列,而不仅仅是一列。

              所以如果你有类似的东西:

              // This will NOT return unique by [id], but unique by (id,name)
              SELECT DISTINCT id, name FROM some_query_with_joins
              
              // This will select unique by [id].
              SELECT id, name FROM some_query_with_joins GROUP BY id
              

              认为 DISTINCT 关键字通过您指定的第一列来区分行是一个常见的错误,但 DISTINCT 是这种方式的通用关键字。

              因此,您必须小心,不要将上述答案视为所有情况下的正确答案...您可能会感到困惑并得到错误的结果,而您想要的只是优化!

              【讨论】:

              • 虽然这个问题is是关于 MySQL 的,但应该注意第二个查询only 在 MySQL 中有效。几乎所有其他 DBMS 都会拒绝第二条语句,因为它是对 GROUP BY 运算符的无效使用。
              • 嗯,“几乎”是一个有问题的定义 :-) 如果您声明一个您已经测试过的特定 DBMS 以查看它会产生错误,这会更有帮助对于这个声明。
              • Postgres、Oracle、Firebird、DB2、SQL Server 初学者。 MySQL:sqlfiddle.com/#!2/6897c/1Postgres:sqlfiddle.com/#!12/6897c/1Oracle:sqlfiddle.com/#!12/6897c/1SQL Server:sqlfiddle.com/#!6/6897c/1
              • 为了迷惑我们:),mysql允许使用select distinct(a), b,这意味着select distinct a, b,这意味着这对不同。
              【解决方案11】:

              如果可以,请选择最简单和最短的 - DISTINCT 似乎更符合您的要求,只是因为它会为您提供所需的答案,而且仅此而已!

              【讨论】:

                【解决方案12】:

                (更多功能说明)

                在某些情况下您必须使用 GROUP BY,例如,如果您想获取每个雇主的雇员人数:

                SELECT u.employer, COUNT(u.id) AS "total employees" FROM users u GROUP BY u.employer
                

                在这种情况下,DISTINCT u.employer 无法正常工作。也许有办法,但我就是不知道。 (如果有人知道如何使用 DISTINCT 进行此类查询,请添加注释!)

                【讨论】:

                  【解决方案13】:

                  SELECT DISTINCT 将始终与 GROUP BY 相同或更快。在某些系统(即 Oracle)上,对于大多数查询,它可能被优化为与 DISTINCT 相同。在其他(例如 SQL Server)上,它可能会快得多。

                  【讨论】:

                    【解决方案14】:

                    如果您对profession 有索引,则这两个是同义词。

                    如果没有,请使用DISTINCT

                    GROUP BY in MySQL 对结果进行排序。你甚至可以这样做:

                    SELECT u.profession FROM users u GROUP BY u.profession DESC
                    

                    并按照DESC 的顺序对您的职业进行排序。

                    DISTINCT 创建一个临时表并将其用于存储重复项。 GROUP BY 做同样的事情,但之后对不同的结果进行排序。

                    所以

                    SELECT DISTINCT u.profession FROM users u
                    

                    如果您在 profession 上没有索引,则速度会更快。

                    【讨论】:

                    • 您可以将ORDER BY NULL 添加到GROUP BY 以避免排序。
                    • 即使按 null 分组仍然较慢
                    • @ThanhTrung:什么比什么慢?
                    • @Quassnoi groupby 比 distinct 慢,即使避免排序
                    • 注意:在 MySQL 8 中,GROUP BY 的顺序限定符已被弃用。
                    【解决方案15】:

                    似乎查询并不完全相同。至少对于 MySQL。

                    比较:

                    1. 描述从 northwind.products 中选择不同的产品名称
                    2. 按产品名称描述从 northwind.products 组中选择的产品名称

                    第二个查询在 Extra 中额外给出“使用文件排序”。

                    【讨论】:

                    • 它们在获得什么方面是相同的,而不是在如何获得方面。理想的优化器会以相同的方式执行它们,但 MySQL 优化器并不理想。根据您的证据,似乎 DISTINCT 会更快 - O(n) vs O(n*log n)。
                    • 那么,“使用文件排序”本质上是一件坏事?
                    • 在这种情况下是这样,因为您不需要排序(如果您需要组,您会这样做)。 MySQL 排序是为了将相同的条目放在一起,然后通过扫描排序的文件来获取组。你只需要不同的,所以你只需要在进行单表扫描时散列你的键。
                    • ORDER BY NULL 添加到GROUP BY 版本中,它们将是相同的。
                    【解决方案16】:

                    如果您不需要执行任何组函数(求和、平均值等,以防您想将数字数据添加到表中),请使用 SELECT DISTINCT。我怀疑它更快,但我没有什么可显示的。

                    无论如何,如果您担心速度,请在列上创建索引。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2022-01-22
                      • 2021-02-09
                      • 1970-01-01
                      • 2016-08-14
                      • 2011-01-29
                      • 1970-01-01
                      • 2012-12-24
                      • 1970-01-01
                      相关资源
                      最近更新 更多