关于mysql5.7的先排序再去重深坑

mysql5.7之前确实可以select * from (select * from table_a order by filed_a desc ) a group by a.filed_b这种写法去重,但是5.7之后,group by 内部优化,只要执行group by,都会重新按照主键的顺序重新排序,再去重,导致如果有遇到去重需要取最新的那条记录的需求一直是有问题的,这个问题我总结了3种方法来解决。

方法1:limit

执行limit后,用explain查看发现会多执行一个DERIVED,不要小瞧它,正是因为他,会让我们之前的先排序再去重可以没有问题的实现,说实话原理上并没有搞的很清楚,有时间可以研究下DERIVED吧

select * from (select * from table_a order by filed_a desc limit 100000000) a group by a.filed_b

方法2:双重group by

其实说白了还是为了让sql执行先执行下DERIVED,再去重才能成功,写法如下

select * from (select * from table_a group by id order by filed_a desc) a group by a.filed_b

 

上述两种方法虽然实现了业务功能,但是你会发现数据量大,其他条件多的情况下,SQL性能差的一逼,条件一多,越来越慢,越来越差。

方法3:代码实现排序去重,SQL只做查询

因为我是做java的,所以代码是java,其实思路有的话,代码实现起来是很方便的,这里用的是lambda表达式

list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparingLong(Object::getXXXId))), ArrayList::new));

这个lambda表达式实现的是去重,只需要我们将查询的数据排序后放进去,去重后,再从list拿到主键list<Long> ids,我们可以把ids当做条件放到sql中,当做参数,原始sql只需要这样既可

select * from table_a where id in(id1,id2,id3) order by filed_a desc

改完之后会发现性能高了会不止一倍,毕竟sql已经变得很简单,但是如果数据多的话,这种方法还是存在问题的,毕竟内存中做去重,数据量大的话,容易内存溢出,而且sql条件会极多,不利于查询

所以如果去重的数据少的话,建议用第三种方法,否则也只能在第一种或者第二种或者其他方法上做文章了,但是性能始终会是到坎。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值