MySQL去重中distinct和group by的区别浅析
小黑孩666 人气:0今天在写业务需要对数据库重复字段进行去重时,因为是去重,首先想到的是distinct关键字。于是一小时过去了。。。。(菜鸟一个,大家轻点骂)
我把问题的过程用sql语句演示给大家演示一下
首先我使用的是mybatis-plus,代码如下
QueryWrapper<ProjectCompany> wrapper = new QueryWrapper<>(); wrapper.select("DISTINCT project_id,company_id,company_name,is_delete").eq("project_id",projectId).eq("is_delete","0");
即 "DISTINCT project_id,company_id,company_name,is_delete"
查出的结果
id=null。这是我不希望看到的。没有id的话,下面的业务就不好走了。
于是我在distinct后面加上了id,distinct查出来的数据就是全部数据了,相当于distinct没起作用。冥思苦想一小时。。。。
后来想到了group by分组,于是用了一下
LambdaQueryWrapper<ProjectCompany> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ProjectCompany::getProjectId,projectId).eq(ProjectCompany::getIsDelete,"0").groupBy(ProjectCompany::getProjectId);
发现查出来的数据也进行去重了,id也有值
所以就很好奇 distinct和group by有啥区别,大概总结以下几点:
distinct适合查单个字段去重,支持单列、多列的去重方式。 单列去重的方式简明易懂,即相同值只保留1个。
多列的去重则是根据指定的去重的列信息来进行,即只有所有指定的列信息都相同,才会被认为是重复的信息。
而 group by 可以针对要查询的全部字段中的部分字段去重,它的作用主要是:获取数据表中以分组字段为依据的其他统计数据。
补充:MySQL中distinct和group by去重性能对比
前言
- MySQL:5.7.17
- 存储引擎:InnoDB
- 实验目的:本文主要测试在某字段有无索引、各种不同值个数情况下,记录对此字段其使用
DISTINCT/GROUP BY
去重的查询语句执行时间,对比两者在不同场景下的去重性能,实验过程中关闭MySQL查询缓存。 - 实验表格:
表名 | 记录数 | 查询字段有无索引 | 查询字段不同值个数 | DISTINCT | GROUP BY |
---|---|---|---|---|---|
tab_1 | 100000 | N | 3 | ||
tab_2 | 100000 | Y | 3 | ||
tab_3 | 100000 | N | 10000 | ||
tab_4 | 100000 | Y | 10000 |
实验过程
1)创建测试表
表创建语句:
DROP TABLE IF EXISTS `tab_1`; CREATE TABLE `tab_1` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `value` int(10) unsigned NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `tab_2`; CREATE TABLE `tab_2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `value` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `idx_value` (`value`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `tab_3`; CREATE TABLE `tab_3` LIKE `tab_1`; DROP TABLE IF EXISTS `tab_4`; CREATE TABLE `tab_4` LIKE `tab_2`;
2)生成测试数据
表数据插入过程:
DROP PROCEDURE IF EXISTS generateRandomData; delimiter $$ -- tblName为插入表,field为插入字段,num为插入字段值上限,count为插入的记录数 CREATE PROCEDURE generateRandomData(IN tblName VARCHAR(30),IN field VARCHAR(30),IN num INT UNSIGNED,IN count INT UNSIGNED) BEGIN -- 声明循环变量 DECLARE i INT UNSIGNED DEFAULT 1; -- 循环插入随机整数1~num,共插入count条数据 w1:WHILE i<=count DO set i=i+1; set @val = FLOOR(RAND()*num+1); set @statement = CONCAT('INSERT INTO ',tblName,'(`',field,'`) VALUES(',@val,')'); PREPARE stmt FROM @statement; EXECUTE stmt; END WHILE w1; END $$ delimiter ;
调用过程随机生成测试数据:
call generateRandomData('tab_1','value',3,100000); INSERT INTO tab_2 SELECT * FROM tab_1; call generateRandomData('tab_3','value',10000,100000); INSERT INTO tab_4 SELECT * FROM tab_3;
3)执行查询语句,记录执行时间
查询语句及对应执行时间如下:
SELECT DISTINCT(`value`) FROM tab_1; SELECT `value` FROM tab_1 GROUP BY `value`; SELECT DISTINCT(`value`) FROM tab_2; SELECT `value` FROM tab_2 GROUP BY `value`; SELECT DISTINCT(`value`) FROM tab_3; SELECT `value` FROM tab_3 GROUP BY `value`; SELECT DISTINCT(`value`) FROM tab_4; SELECT `value` FROM tab_4 GROUP BY `value`;
4)实验结果
表名 | 记录数 | 查询字段有无索引 | 查询字段不同值个数 | DISTINCT | GROUP BY |
---|---|---|---|---|---|
tab_1 | 100000 | N | 3 | 0.058s | 0.059s |
tab_2 | 100000 | Y | 3 | 0.030s | 0.027s |
tab_3 | 100000 | N | 10000 | 0.072s | 0.073s |
tab_4 | 100000 | Y | 10000 | 0.047s | 0.049s |
实验结论
MySQL 5.7.17中使用distinct和group by进行去重时,性能相差不大
实验过程及结论,如有不足之处,欢迎指正,此实验结论仅供参考。
总结
加载全部内容