取group by每个分组中最新的一条元素
- 取group by每个分组中最新的一条元素
- in 和 inner join比较
- 需求:有一个日志表,里面包含了很多人的实时记录,因为所有记录需要留存,所以一个人可能有多条记录。分布在不同时间段。现在取出所有今天有记录的人的最新的一条记录。
- 例如:取出下表中每个人当天最新的一条记录
- (今天是2020-11-11 剁手了没,贫穷的我只能来写博客了(手动滑稽))–(!!!!!!呸,今天已经十二月四号了,博客还躺在草稿箱没发出去。)。
取group by每个分组中最新的一条元素
日志id(log_id) | 人员id(person_id) | 姓名(name) | 时间(taccess_ime) | 地点 (area) | 状态 (status) |
1 | 001 | 张三 | 2020-11-11 12:23:00 | 区域1 | 0 |
2 | 001 | 张三 | 2020-11-11 12:50:00 | 区域1 | 1 |
3 | 002 | 李四 | 2020-11-01 02:50:00 | 区域2 | 0 |
4 | 002 | 李四 | 2020-11-11 15:09:00 | 区域2 | 1 |
5 | 003 | 王二蛋 | 2020-11-01 02:50:00 | 区域2 | 0 |
6 | 004 | 王三狗 | 2020-11-11 15:09:00 | 区域2 | 1 |
取出结果应该是这样的:
日志id(log_id) | 人员id(person_id) | 姓名(name) | 时间(taccess_ime) | 地点 (area) | 状态 (status) |
2 | 001 | 张三 | 2020-11-11 12:50:00 | 区域1 | 1 |
4 | 002 | 李四 | 2020-11-11 15:09:00 | 区域2 | 1 |
6 | 003 | 王三狗 | 2020-11-11 15:09:00 | 区域2 | 1 |
网上找了一堆,最后找到的是这个。
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不会产生两表合并的临时表。
写在最后: 很久没写博客了,有些零散,最近在忙一些事情。也算忙得差不多了。继续记录成长吧。博客和思想如有错误还望路过大佬们指正。