取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	
				)

我特么就千八百条数据,给我查了十秒钟,玩个蛇皮。

mysql groupby 取最新的一条数据 group by取最新的一条值_sql


想要获取完整字段的数据,用上面那个肯定不得行。最后自己想到了内连接。如下,感觉还凑合用吧。也能查出结果,质变的查询耗时。

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 groupby 取最新的一条数据 group by取最新的一条值_mysql_02

  • 后来自己也去专门研究了下,数据库原理。博主用的是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不会产生两表合并的临时表。

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