SQL 去重效率天差地别?GROUP BY 和 DISTINCT 的底层厮杀

GROUP BYDISTINCT 是 SQL 中用于去重的两种方式,但它们的核心用途、底层原理和性能表现差异显著。以下是详细对比:

1. 核心用途差异

功能 GROUP BY DISTINCT
主要目的 分组聚合(如计算每组的 SUMCOUNT 返回结果集的唯一行(去重)
聚合函数 必须搭配聚合函数(如 SUMAVG 不支持聚合函数,仅返回原始字段
示例 GROUP BY dept_id + SUM(salary) DISTINCT city

2. 底层执行原理

GROUP BY 的执行流程

  1. 分组阶段
    • 按照 GROUP BY 指定的字段对结果集进行排序(如果未使用索引)。
    • 将相同值的行放入同一个组中。
  2. 聚合阶段
    • 对每个组应用聚合函数(如 SUMCOUNT),生成单行结果。
  3. 索引优化
    • 如果 GROUP BY 字段有索引,数据库会直接利用索引的有序性快速分组(避免排序)。
    • 例如,MySQL 的 filesort 操作可被索引避免。

DISTINCT 的执行流程

  1. 排序/哈希去重
    • 排序法:对结果集按所有选择的字段排序,相邻重复行只保留一行。
    • 哈希法:构建哈希表,遍历结果集时丢弃哈希冲突的重复行。
  2. 索引优化
    • 如果 SELECT 的字段包含索引,数据库直接扫描索引(无需回表)。
    • 例如,SELECT DISTINCT email 可通过 email 索引快速去重。

3. 性能对比

场景 GROUP BY DISTINCT
无聚合的简单去重 需额外排序开销,性能较差 专为去重优化,性能更好
带聚合函数的分组 直接分组聚合,性能最优 无法实现,必须用 GROUP BY
索引优化 依赖索引避免排序(如覆盖索引) 依赖索引避免回表(如唯一索引)
大数据量去重 可能触发磁盘临时文件(排序溢出) 哈希法更高效(内存足够时)

4. 示例对比

假设有表 orders

user_id product amount
1 A 100
1 B 200
2 A 150

场景1:统计每个用户的总金额(聚合)

sql 复制代码
SELECT user_id, SUM(amount)  -- 必须用 GROUP BY
FROM orders
GROUP BY user_id;
  • 结果

    user_id SUM(amount)
    1 300
    2 150

场景2:列出所有购买过的产品(去重)

sql 复制代码
SELECT DISTINCT product;  -- 简洁写法
-- 等价于(但性能更差):
SELECT product FROM orders GROUP BY product;
  • 结果

    product
    A
    B

5. 进阶区别

  1. NULL 处理

    • DISTINCT 将所有 NULL 视为相同值(只保留一个)。
    • GROUP BY 同样将 NULL 分为一组(如果字段允许为 NULL)。
  2. 多字段组合

    • DISTINCT col1, col2 去重的是两个字段的组合值。
    • GROUP BY col1, col2 对组合字段分组,需搭配聚合函数。
  3. ORDER BY 的联用

    • DISTINCT 先去重,再按结果排序。
    • GROUP BY 先分组,聚合后按结果排序(索引可优化排序)。

6. 选择建议

需求 最佳选择 理由
简单去重(无聚合) DISTINCT 语法简洁,性能优化更好
分组聚合(如统计、平均值) GROUP BY 必须搭配聚合函数
多字段去重 + 排序 DISTINCT + 索引 利用索引避免排序
大数据量分组 GROUP BY + 索引 索引可避免 filesort

总结

  • GROUP BY 是为聚合而生,必须搭配聚合函数,底层通过排序或哈希实现分组。
  • DISTINCT 是纯粹的去重工具,直接丢弃重复行,语法更简洁。
  • 性能关键:合理使用索引(覆盖索引、唯一索引)可大幅提升两者效率。
相关推荐
Mahir081 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
IT_陈寒5 小时前
Redis缓存击穿把我整不会了,原来还有这手操作
前端·人工智能·后端
kyriewen6 小时前
面试官让我查各部门工资最高的员工,我用AI三秒写出窗口函数,他愣了
后端·mysql·面试
文心快码BaiduComate6 小时前
干货|Comate Harness Engineering工程实践指南
前端·后端·程序员
光辉GuangHui6 小时前
Agent Skill 也需要测试:如何搭建 Skill 评估框架
前端·后端·llm
我是谁的程序员6 小时前
Mac 上生成 AppStoreInfo.plist 文件,App Store 上架
后端·ios
irving同学462386 小时前
Node 后端实战:JWT 认证与生产级错误处理
前端·后端
Master_Azur6 小时前
单元测试——Junit单元测试框架
后端
用户8356290780516 小时前
使用 Python 进行 Word 邮件合并
后端
用户8356290780517 小时前
Python 操作 PowerPoint OLE 对象
后端·python