SQL 去重效率天差地别?GROUP BY 和 DISTINCT 的底层厮杀
GROUP BY 和 DISTINCT 是 SQL 中用于去重的两种方式,但它们的核心用途、底层原理和性能表现差异显著。以下是详细对比:
1. 核心用途差异
功能 | GROUP BY | DISTINCT |
主要目的 | 分组聚合(如计算每组的 SUM 、 COUNT ) | 返回结果集的唯一行(去重) |
聚合函数 | 必须搭配聚合函数(如 SUM 、 AVG ) | 不支持聚合函数,仅返回原始字段 |
示例 | GROUP BY dept_id + SUM(salary) | DISTINCT city |
2. 底层执行原理
GROUP BY 的执行流程
- 分组阶段 :
- 按照 GROUP BY 指定的字段对结果集进行排序(如果未使用索引)。
- 将相同值的行放入同一个组中。
- 聚合阶段 :
- 对每个组应用聚合函数(如 SUM 、 COUNT ),生成单行结果。
- 索引优化 :
- 如果 GROUP BY 字段有索引,数据库会直接利用索引的有序性快速分组(避免排序)。
- 例如,MySQL 的 filesort 操作可被索引避免。
DISTINCT 的执行流程
- 排序/哈希去重 :
- 排序法 :对结果集按所有选择的字段排序,相邻重复行只保留一行。
- 哈希法 :构建哈希表,遍历结果集时丢弃哈希冲突的重复行。
- 索引优化 :
- 如果 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:统计每个用户的总金额(聚合)
SELECT user_id, SUM(amount) -- 必须用 GROUP BYFROM ordersGROUP BY user_id;- 结果 :
user_id | SUM(amount) |
1 | 300 |
2 | 150 |
场景2:列出所有购买过的产品(去重)
SELECT DISTINCT product; -- 简洁写法-- 等价于(但性能更差):SELECT product FROM orders GROUP BY product;- 结果 :
product |
A |
B |
5. 进阶区别
- NULL 处理 :
- DISTINCT 将所有 NULL 视为相同值(只保留一个)。
- GROUP BY 同样将 NULL 分为一组(如果字段允许为 NULL )。
- 多字段组合 :
- DISTINCT col1, col2 去重的是两个字段的组合值。
- GROUP BY col1, col2 对组合字段分组,需搭配聚合函数。
- 与 ORDER BY 的联用 :
- DISTINCT 先去重,再按结果排序。
- GROUP BY 先分组,聚合后按结果排序(索引可优化排序)。
6. 选择建议
需求 | 最佳选择 | 理由 |
简单去重(无聚合) | DISTINCT | 语法简洁,性能优化更好 |
分组聚合(如统计、平均值) | GROUP BY | 必须搭配聚合函数 |
多字段去重 + 排序 | DISTINCT + 索引 | 利用索引避免排序 |
大数据量分组 | GROUP BY + 索引 | 索引可避免 filesort |
总结
- GROUP BY 是为聚合而生,必须搭配聚合函数,底层通过排序或哈希实现分组。
- DISTINCT 是纯粹的去重工具,直接丢弃重复行,语法更简洁。
- 性能关键 :合理使用索引(覆盖索引、唯一索引)可大幅提升两者效率。

文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有