【问题标题】:SQL: GROUP BY vs. DISTINCT. What is the best one in this situation?SQL:GROUP BY 与 DISTINCT。在这种情况下,什么是最好的?
【发布时间】:2017-11-24 14:05:32
【问题描述】:

我对数据库不太感兴趣,我有以下疑问与我在 MySql 数据库上运行的查询有关。

我有这个问题:

SELECT
    CD.id                AS id, 
    CD.commodity_name_en AS commodity_name_en

FROM MarketDetails AS MD
INNER JOIN MarketDetails_CommodityDetails AS MD_CD
      ON MD.id = MD_CD.market_details_id 
INNER JOIN CommodityDetails AS CD
      on MD_CD.commodity_details_id = CD.id
WHERE MD.localization_id = 1

返回类似这样的内容(代表某些市场的商品列表):

id                   commodity_name_en                                                                                                                                                                                                                                              
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1                    Rice-Asia                                                                                                                                                                                                                                                      
2                    Apple banana                                                                                                                                                                                                                                                   
3                    Avocado                                                                                                                                                                                                                                                        
4                    Red onion                                                                                                                                                                                                                                                      
5                    White onion                                                                                                                                                                                                                                                    
6                    Green Beans                                                                                                                                                                                                                                                    
7                    Bell pepper                                                                                                                                                                                                                                                    
8                    Carrot                                                                                                                                                                                                                                                         
9                    Tomatoes                                                                                                                                                                                                                    
10                   Irish potatoes                                                                                                                                                                                                                                                 
11                   Maize                                                                                                                                                                                                                                                          
1                    Rice-Asia                                                                                                                                                                                                                                                      
3                    Avocado                                                                                                                                                                                                                                                        
5                    White onion                                                                                                                                                                                                                                                    
8                    Carrot                                                                                                                                                                                                                                                         
11                   Maize                                                                                                                                                                                                                                                          
2                    Apple banana                                                                                                                                                                                                                                                   
7                    Bell pepper                                                                                                                                                                                                                                                    
9                    Tomatoes                                                                                                                                                                                                                    
10                   Irish potatoes                                                                                                                                                                                                                                                 
1                    Rice-Asia   

如您所见,这些商品可以出现多次(因为特定商品可以在多个市场上销售)。

我想更改我的查询,使每个商品只出现一次(因为最后我想要所有可能商品的列表而不重复)。

所以我知道我可以这样做:

SELECT
    CD.id                AS id, 
    CD.commodity_name_en AS commodity_name_en

FROM MarketDetails AS MD
INNER JOIN MarketDetails_CommodityDetails AS MD_CD
      ON MD.id = MD_CD.market_details_id 
INNER JOIN CommodityDetails AS CD
      on MD_CD.commodity_details_id = CD.id
WHERE MD.localization_id = 1
GROUP BY id

我按 ID 分组,但我也可以按名称分组(相同)。

我的疑问是:我可以使用 distinct 语句来获得相同的行为吗?

在这里阅读似乎可以解决问题:https://www.tutorialspoint.com/sql/sql-distinct-keyword.htm

所以我也尝试了这个解决方案,它似乎返回了相同的结果

SELECT DISTINCT
    CD.id                AS id, 
    CD.commodity_name_en AS commodity_name_en

FROM MarketDetails AS MD
INNER JOIN MarketDetails_CommodityDetails AS MD_CD
      ON MD.id = MD_CD.market_details_id 
INNER JOIN CommodityDetails AS CD
      on MD_CD.commodity_details_id = CD.id
WHERE MD.localization_id = 1

那么 DISTINCTGROUP BY 解决方案之间的确切区别是什么?在我这种情况下,最聪明的是什么?

谢谢

【问题讨论】:

  • 我建议对每个查询运行 EXPLAIN 并发布结果,这将突出每种方法的效率
  • 根据@PaulDixon 的评论,我还将对每个时间进行基准测试。
  • DISTINCT 查询通常可以通过GROUP BY 在 MySQL 的底层实现。我不希望这两个查询的执行方式有太大差异。
  • DISTINCTGROUP BY 可以做同样的事情,但它们有不同的用途。因此,请相应地使用它们,以使您的查询尽可能具有可读性。当您有重复的行并想要删除重复的行时,请使用 DISTINCT。这很少需要。大多数情况下DISTINCT 表示您不必要地创建了重复项,就像您的情况一样。仅当您想要聚合行时才使用GROUP BY,例如获取总和、最大值或计数。

标签: mysql sql database group-by distinct


【解决方案1】:

忘记使用任何一个版本。如果您只想要一个表中的列,请改用exists

SELECT CD.id, CD.commodity_name_en
FROM CommodityDetails CD
WHERE EXISTS (SELECT 1
              FROM MarketDetails MD INNER JOIN 
                   MarketDetails_CommodityDetails MD_CD
                   ON MD.id = MD_CD.market_details_id 
              WHERE MD_CD.commodity_details_id = CD.id AND
                    MD.localization_id = 1
             );

有了这个版本,MySQL 不需要对整个结果集进行聚合——这可以节省大量成本。这应该能够利用用于原始查询的索引。

注意:我为您的列别名删除了 asCD.id 的默认别名 id。没有理由明确指定这一点(除非您真的喜欢打字和冗长的查询)。

至于您的具体问题,在 cmets 中已得到解答 -- DISTINCTGROUP BY 应该具有非常相似的性能。

【讨论】:

    【解决方案2】:

    不要加入所有内容,以后必须从该结果集中删除。

    您想选择某些市场中存在的商品。因此,您可以从商品表中进行选择,并在 WHERE 子句(使用 EXISTSIN 子句)中查找它们的市场。

    select id, commodity_name_en
    from commoditydetails
    where id in
    (
      select md_cd.commodity_details_id
      from marketdetails_commoditydetails md_cd
      join marketdetails md on md.id = md_cd.market_details_id
      where md.localization_id = 1
    );
    

    或者,如果你更喜欢这样,即使没有任何加入:

    select id, commodity_name_en
    from commoditydetails
    where id in
    (
      select commodity_details_id
      from marketdetails_commoditydetails
      where market_details_id in (select id from marketdetails where md.localization_id = 1)
    );
    

    【讨论】:

    • 为什么要节省时间?
    • 首先,在编写 SQL 时,我们希望查询具有可读性和可维护性。这应该是我们首先考虑的。如果要选择商品,就选择商品,而不是与市场结合的商品。至于速度:聚合和删除重复项是相当缓慢的过程。必须首先订购所有数据才能完成此操作。对于大型表来说,这可能是一项艰巨的任务。 (对于小桌子,这不会有太大区别。)
    • 无论如何:仅在遇到性能问题时才考虑加快查询速度。不要混淆查询,因为您认为这可能会以某种方式欺骗 DBMS 生成更好的执行计划。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多