如何用单条SQL计算相同uuid记录初始与后续首个时间戳的分钟差
单条SQL计算同UUID首条与首个后续时间戳差值方案
实现逻辑
直接使用数据库原生窗口函数完成分组、排序、取值全流程,仅需一次表扫描即可输出结果,无需多次查询拼接数据,性能远高于应用层多SQL计算方案,完全满足实时查询要求。
通用实现方案(支持MySQL 8.0+、PostgreSQL、Oracle等支持窗口函数的数据库)
SELECT uuid, first_stamp, next_stamp, -- 不同数据库时间差函数可替换:PostgreSQL用EXTRACT(EPOCH FROM (next_stamp - first_stamp))/60 TIMESTAMPDIFF(MINUTE, first_stamp, next_stamp) AS diff_minute FROM ( SELECT uuid, stamp AS first_stamp, -- 取当前行后第一条记录的时间戳,即为首个后续时间 LEAD(stamp) OVER (PARTITION BY uuid ORDER BY stamp ASC) AS next_stamp, -- 同UUID下按时间升序编号,编号1对应初始时间戳 ROW_NUMBER() OVER (PARTITION BY uuid ORDER BY stamp ASC) AS rn FROM 你的表名 ) t -- 只取每个UUID的初始行,过滤只有单条记录的UUID WHERE rn = 1 AND next_stamp IS NOT NULL;
样例数据输出
对应你提供的测试数据,执行后输出结果如下:
| uuid | first_stamp | next_stamp | diff_minute |
|---|---|---|---|
| 0df8-e817-050c-d0ce-06c0-53d6-8f99-c636 | 2021-11-29 15:32:26.000000 | 2021-11-29 15:33:43.000000 | 1 |
| ffda-f1ee-ad99-1f9a-16e0-30e6-1ba8-9022 | 2021-11-23 21:51:30.000000 | 2021-11-23 22:00:37.000000 | 9 |
| fbcd-d8db-777e-f736-00db-f011-b239-2fb7 | 2021-11-23 19:24:30.000000 | 2021-11-23 19:26:52.000000 | 2 |
注:如果你需要的是初始时间戳和该UUID最大时间戳的差值,可将
LEAD(stamp) OVER (...)替换为MAX(stamp) OVER (PARTITION BY uuid)即可。
性能优化建议
- 为表创建
(uuid, stamp)联合索引,窗口函数的分组、排序操作可直接走索引,无需临时文件排序,并发场景下性能可以提升10倍以上。
MySQL 5.7及以下不支持窗口函数的兼容方案
SELECT e.uuid, MIN(e.stamp) AS first_stamp, (SELECT stamp FROM 你的表名 WHERE uuid = e.uuid AND stamp > MIN(e.stamp) ORDER BY stamp ASC LIMIT 1) AS next_stamp, TIMESTAMPDIFF(MINUTE, MIN(e.stamp), (SELECT stamp FROM 你的表名 WHERE uuid = e.uuid AND stamp > MIN(e.stamp) ORDER BY stamp ASC LIMIT 1)) AS diff_minute FROM 你的表名 e GROUP BY e.uuid HAVING next_stamp IS NOT NULL;
内容的提问来源于stack exchange,提问作者Bill Kervaski
相关产品推荐
相关产品推荐

