【问题标题】:GROUP BY x vs DISTINCT( x )GROUP BY x vs DISTINCT( x )
【发布时间】:2014-06-20 21:28:14
【问题描述】:

如果我有一个带有重复 ID 的表,如果我使用 GROUP BY id 和使用 SELECT DISTINCT(id) 一样,我会得到相同的结果,对吧?

那么我什么时候应该更喜欢一种选择呢?

【问题讨论】:

  • 不需要将列和/或表达式包装在括号中; DISTINCT 关键字适用于整个 SELECT 列表。 id 周围的括号不会影响查询结果或执行计划。
  • group by 更通用。 distinct 真的只是一个简写。真正需要它的唯一时间是当您执行 select distinct * 时,因为不允许使用 group by *。也就是说,首先要专注于学习和使用group by
  • ...虽然DISTINCT * 看起来毫无意义。 @doub1ejack 通常,在没有任何聚合函数的情况下,不应将 GROUP BY 用作 DISTINCT 的替代品。在某些情况下,它可能会产生误导性结果。

标签: mysql group-by distinct


【解决方案1】:

如果你需要聚合函数,你应该使用GROUP BY,比如SUMMAX等等。

如果您只需要对列进行分组,它们是相同的(并且使用相同的计划)。

请注意DISTINCT不是函数,所以这个子句:

SELECT DISTINCT(id), othercol

相同(列顺序除外)
SELECT DISTINCT othercol, (id)

或者只是

SELECT DISTINCT othercol, id

如果有相同 id 但不同 othercol 的记录,可能仍会在 id 上为您提供重复项。

【讨论】:

  • "如果存在具有相同 id 但不同 othercol 的记录,则可能仍会在 id 上为您提供重复项" +1。 DISTINCT 表示行本身是唯一的,表示所有返回列的组合。
  • 所以我的前提,即 GROUP BY 和 DISTINCT 返回相同的结果,不完全准确吗?如果我理解正确,DISTINCT 返回唯一行,但 GROUP BY 返回行~被特定字段折叠。 ..尽管在比较简单查询时这通常看起来相同。很高兴知道 - 谢谢。
【解决方案2】:

DISTINCT 和 GROUP BY 通常会生成相同的查询计划,因此两种查询结构的性能应该相同。应该使用 GROUP BY 将聚合运算符应用于每个组。如果您只需要删除重复项,请使用 DISTINCT。如果您使用子查询,则该查询的执行计划会有所不同,因此在这种情况下,您需要在决定哪个更快之前检查执行计划。

Example of DISTINCT:
 SELECT DISTINCT Employee, Rank
 FROM Employees

Example of GROUP BY:
 SELECT Employee, Rank
 FROM Employees
 GROUP BY Employee, Rank

Example of GROUP BY with aggregate function:
 SELECT Employee, Rank, COUNT(*) EmployeeCount
 FROM Employees
 GROUP BY Employee, Rank 

参考:Pinal Dave (http://blog.SQLAuthority.com)

【讨论】:

    【解决方案3】:

    只是额外的信息:

    如果您要查询索引字段并且有 LIMIT,最好使用 GROUP BY 而不是 DISTINCT,因为它将使用索引,而不是临时表

    查看以下链接:


    例子:

    MariaDB [my_db]> EXPLAIN SELECT DISTINCT p.data_prefix FROM my_table p;
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    | id   | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                    |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    |    1 | SIMPLE      | p     | range | NULL          | data_prefix | 33      | NULL |   18 | Using index for group-by |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    1 row in set (0.00 sec)
    
    MariaDB [my_db]> EXPLAIN SELECT DISTINCT p.data_prefix FROM my_table p limit 0,40;
    +------+-------------+-------+-------+---------------+------------+---------+------+------+-------------------------------------------+
    | id   | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                                     |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+-------------------------------------------+
    |    1 | SIMPLE      | p     | range | NULL          | data_prefix | 33      | NULL |   18 | Using index for group-by; Using temporary |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+-------------------------------------------+
    1 row in set (0.00 sec)
    
    MariaDB [my_db]> EXPLAIN SELECT p.data_prefix FROM my_table p group by p.data_prefix;
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    | id   | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                    |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    |    1 | SIMPLE      | p     | range | NULL          | data_prefix | 33      | NULL |   18 | Using index for group-by |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    1 row in set (0.00 sec)
    
    MariaDB [my_db]> EXPLAIN SELECT p.data_prefix FROM my_table p group by p.data_prefix limit 0,40;
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    | id   | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                    |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    |    1 | SIMPLE      | p     | range | NULL          | data_prefix | 33      | NULL |   18 | Using index for group-by |
    +------+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
    1 row in set (0.00 sec)
    
    MariaDB [my_db]>
    

    【讨论】:

      【解决方案4】:

      您可能更喜欢group by 而不是distinct 的示例。考虑需要在不同结果集上应用window function不一定是 row_number())的场景。尊重操作顺序,您将不得不使用 distinct 进行类似的操作

      select id, row_number() over (order by id) as rn
      from (select distinct id from my_table) t;
      

      不使用group by的子查询也可以达到同样的效果

      select id, row_number() over (order by id) as rn 
      from my_table
      group by id;
      

      这是可能的,因为window functionsgroup by 之后但在distinct 之前应用

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-09-12
        • 2020-04-05
        • 1970-01-01
        • 1970-01-01
        • 2019-02-28
        • 2010-09-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多