MySQL中的数据去重,该用DISTINCT还是GROUP BY?
|
admin
2025年12月3日 11:54
本文热度 270
|
在MySQL中进行数据去重时,DISTINCT 和 GROUP BY 均可实现去重效果,但两者在核心用途、底层原理、性能表现及适用场景上存在显著差异。以下是综合对比及选择建议:
⚙️ 一、核心差异
| 特性 | DISTINCT | GROUP BY |
|---|
| 主要目的 | 返回唯一行(去重) | 分组后聚合(如 SUM、COUNT) |
| 是否支持聚合函数 | 不支持(仅返回原始字段) | 必须搭配聚合函数 |
| 语法简洁度 | 更简洁(如 SELECT DISTINCT col) | 需显式指定分组字段 |
| NULL值处理 | 所有NULL视为相同值(保留一个) | 所有NULL分为一组 |
示例对比:
- 去重场景:
SELECT DISTINCT city FROM users; - 聚合场景:
SELECT city, COUNT(*) FROM users GROUP BY city; 1367
⛓️ 二、底层原理与性能
执行流程:
DISTINCT :- 排序法:对结果集全字段排序,相邻重复行仅保留一行(如早期MySQL)。
- 哈希法:构建哈希表,丢弃哈希冲突的重复行(如 PostgreSQL)。
GROUP BY :- 先按分组字段排序(无索引时触发
filesort),再对每组应用聚合函数生成单行结果。 - 若分组字段有索引,直接利用索引有序性避免排序 147。
性能对比(基于100W数据测试 5):
| 场景 | DISTINCT | GROUP BY |
|---|
| 简单去重(无聚合) | 约0.8秒 | 约0.75秒(差异≈5%) |
| 分组聚合 | 无法实现 | 高效(需索引优化) |
优化关键:
- 索引覆盖:对去重/分组字段创建索引(如
CREATE INDEX idx ON table(col)),可避免全表扫描和排序。 - 避免大字段:文本类型(如
TEXT)去重性能差,改用哈希值(MD5(col))或整数类型 124。 - 减少字段数:多列去重时,字段越少计算开销越低 25。
🚀 三、应用场景选择
| 需求 | 推荐方式 | 理由 |
|---|
| 仅需去重,无聚合 | DISTINCT | 语法简洁,性能略优(大数据量时哈希法更高效)57 |
| 去重+统计(如计数) | GROUP BY | 支持聚合函数(COUNT(), SUM()等),扩展性强 57 |
| 多字段去重+排序 | DISTINCT+索引 | 先利用索引去重,再通过 ORDER BY 排序 6 |
| 大数据量分组聚合 | GROUP BY+索引 | 索引避免 filesort,结合 LIMIT 分页优化性能 57 |
| 保留重复组首条记录 | ROW_NUMBER() | 复杂场景(如按时间保留最新记录):<br>SELECT ... WHERE rn=1 14 |
典型示例:
- 统计不同城市的用户数:
SELECT city, COUNT(*) FROM users GROUP BY city; -- GROUP BY 支持聚合
- 仅获取不重复的产品列表:
SELECT DISTINCT product FROM orders; -- DISTINCT 更简洁
💎 四、总结与建议
性能优先:
- 两者在简单去重场景性能接近(差异<5%),优先选语法更直观的
DISTINCT 57。 - 务必为去重字段添加索引,否则
GROUP BY 可能触发低效的 filesort。
功能扩展:
- 需进一步统计、过滤(
HAVING)或排序时,GROUP BY 是唯一选择 57。
避坑指南:
- 避免对大型文本字段直接去重(改用哈希或子查询)。
- 若数据本身无重复(如主键查询),无需使用
DISTINCT 增加开销 12。
终极建议:
- 简单去重 →
DISTINCT - 聚合分析 →
GROUP BY - 复杂逻辑 →
ROW_NUMBER() OVER (PARTITION BY)
通过合理选择并结合索引优化,两者均能高效应对百万级数据去重需求,但明确业务目标(纯去重 or 聚合)是选择的关键 🔑。
该文章在 2025/12/3 16:17:18 编辑过