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 是纯粹的去重工具,直接丢弃重复行,语法更简洁。
  • 性能关键:合理使用索引(覆盖索引、唯一索引)可大幅提升两者效率。
相关推荐
uhakadotcom17 分钟前
使用postgresql时有哪些简单有用的最佳实践
后端·面试·github
IT毕设实战小研21 分钟前
基于Spring Boot校园二手交易平台系统设计与实现 二手交易系统 交易平台小程序
java·数据库·vue.js·spring boot·后端·小程序·课程设计
bobz96530 分钟前
QT 字体
后端
泉城老铁32 分钟前
Spring Boot 中根据 Word 模板导出包含表格、图表等复杂格式的文档
java·后端
用户40993225021234 分钟前
如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法?
后端·github·trae
风象南39 分钟前
开发者必备工具:用 SpringBoot 构建轻量级日志查看器,省时又省力
后端
RainbowSea1 小时前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 04
java·spring boot·后端
楽码1 小时前
理解自动修复:编程语言的底层逻辑
后端·算法·编程语言
RainbowSea1 小时前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 03
java·spring boot·后端
Young55661 小时前
RAG?你真的了解RAG吗?
人工智能·后端