SQL查询:取group by每个分组中最新的一条元素

取group by每个分组中最新的一条元素

  • 需求:有一个日志表,里面包含了很多人的实时记录,因为所有记录需要留存,所以一个人可能有多条记录。分布在不同时间段。现在取出所有今天有记录的人的最新的一条记录。

  • 例如:取出下表中每个人当天最新的一条记录

  • (今天是2020-11-11 剁手了没,贫穷的我只能来写博客了(手动滑稽))–(!!!!!!呸,今天已经十二月四号了,博客还躺在草稿箱没发出去。)。

取group by每个分组中最新的一条元素
日志id(log_id)人员id(person_id)姓名(name)时间(taccess_ime)地点 (area)状态 (status)
1001张三2020-11-11 12:23:00区域10
2001张三2020-11-11 12:50:00区域11
3002李四2020-11-01 02:50:00区域20
4002李四2020-11-11 15:09:00区域21
5003王二蛋2020-11-01 02:50:00区域20
6004王三狗2020-11-11 15:09:00区域21

取出结果应该是这样的:

日志id(log_id)人员id(person_id)姓名(name)时间(taccess_ime)地点 (area)状态 (status)
2001张三2020-11-11 12:50:00区域11
4002李四2020-11-11 15:09:00区域21
6003王三狗2020-11-11 15:09:00区域21

网上找了一堆,最后找到的是这个。

select SUBSTRING_INDEX(group_concat(access_log_id order by `ACCESS_TIME` desc),',',1) id from t_access_log tac
	where  date(ACCESS_TIME) = curdate()
	GROUP BY tac.PERSON_ID

结果查出来的结果是这个。只查出来一列主键。

日志id(log_id)
2
4
6

然后自己优化了下,因为所在公司业务比较简单,没有用到高并发的情况,所以很多时候查询都没遇到过查询瓶颈。顶多就是之前在for循环里嵌套了个查询导致查询飙到3s+;也是严重影响界面效果。这次哥们儿想当然的用了一手嵌套查询,写的时候自己造了几条数,差异并不明显。但是导了百来条数据进去。查询语句如下,猜猜结果如何:

	select * from t_access_log where access_log_id in(
				select SUBSTRING_INDEX(group_concat(access_log_id order by `ACCESS_TIME` desc),',',1) from t_access_log tac
				where  date(ACCESS_TIME) = curdate()
				GROUP BY tac.PERSON_ID	
				)
				


我特么就千八百条数据,给我查了十秒钟,玩个蛇皮。
在这里插入图片描述
想要获取完整字段的数据,用上面那个肯定不得行。最后自己想到了内连接。如下,感觉还凑合用吧。也能查出结果,质变的查询耗时。

select ta.* from t_access_log ta
inner join (
	select SUBSTRING_INDEX(group_concat(access_log_id order by `ACCESS_TIME` desc),',',1) id from t_access_log tac
	where  date(ACCESS_TIME) = curdate()
	GROUP BY tac.PERSON_ID
) a on ta.ACCESS_LOG_ID = a.id

在这里插入图片描述

  • 后来自己也去专门研究了下,数据库原理。博主用的是MySql,Mysql底层是B+树,之所以查询快,是因为数据根据主键进行了自增。B+树相当于就是一本书的目录,索引其实也是一样的原理。
  • 数据库通过树可以快速定位我们我们想要的数据在哪一页那个位置。MySql是分页查询,每次根据B+树找对对应页,把这页数据取出来,在里面找。(温馨提示每页数据16Kb,面试题被问到过)这也是我们数据库优化建议尽量用索引,可以提高速率的原因,个人理解其实每个表的主键就是单表默认的一种索引。我们知道根据主键查询是最快的。
  • 当我用 in 的时候,我在前面没有做其他条件限制,相当于我依次要把所有记录一条一条取出来,再和我嵌套里面临时表依次进行比较。由于临时表里的数据是未知的。所以我有一千条数据,就要取一千次,比较一千次;临时表里面再有一千条数据;就要比较1000x1000次,不知道会不会生成一千次临时表(盲区)。当我们数据稍多一点,用in直接就鸡鸡。
in 和 inner join比较
  • 1、 结果集比较小的情况下(比如只有几十条)用in的效率高于关联,
  • 2、如果结果集比较大的情况下则用inner join的效率高于用in,
  • 但是注意in和inner join在某些情况下结果是不一样的:当子查询中有重复数据时,join的结果也是会重复的
  • in的结果是不会有重复的,对非主键进行join时,join的结果是有重复的。如果说还有另一个区别的话就是join会产生一个两表合并的临时表,in不会产生两表合并的临时表。

写在最后: 很久没写博客了,有些零散,最近在忙一些事情。也算忙得差不多了。继续记录成长吧。博客和思想如有错误还望路过大佬们指正。

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

private_static

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值