取下一行的值
错行取值是计算相邻记录关系的标准手段:把下一行的时间戳取到当前行,两者相减就是这次操作的持续时长;相邻两条日志之间做差,就能看出间隔是否异常。这类计算的核心是让窗口有确定的顺序,同一时刻可能有多条记录时还要再加一个次级排序键,否则相邻关系在多次执行间会变化。
基本信息
| 适用平台 | MySQL 8.0 / PostgreSQL 12 及以上 |
|---|---|
| 函数形式 | 取值函数带表达式、偏移量与默认值三个可选部分 |
| 边界行为 | 超出范围时返回默认值,未指定则为空值 |
| 排序要求 | 必须给出稳定排序,否则相邻关系不确定 |
| 时间差写法 | MySQL 用专用时间差函数,PostgreSQL 用时间戳相减 |
典型使用场景
- 流程耗时:相邻两个节点的时间差就是这一步的耗时
- 登录间隔:上次登录与本次登录的时间差
- 异常检测:连续两次操作间隔过短,可能为脚本行为
- 分页游标:取下一行的主键作为下一页的起始位置
- 任务排队分析:相邻任务之间的等待时长
取值与求差
取值与求差
-- 取下一行的时间戳并求间隔(MySQL 写法)
SELECT id, started_at,
LEAD(started_at) OVER (ORDER BY started_at) AS next_started,
TIMESTAMPDIFF(SECOND, started_at,
LEAD(started_at) OVER (ORDER BY started_at)) AS gap_seconds
FROM jobs
ORDER BY started_at;
-- PostgreSQL:时间戳直接相减得到间隔
-- SELECT id, started_at,
-- LEAD(started_at) OVER (ORDER BY started_at) AS next_started,
-- EXTRACT(EPOCH FROM (LEAD(started_at) OVER (ORDER BY started_at) - started_at))
-- AS gap_seconds
-- FROM jobs ORDER BY started_at;
-- 指定偏移量与边界默认值:取后两行,末行给默认值
SELECT id, LEAD(id, 2, -1) OVER (ORDER BY id) AS next2 FROM jobs;
-- 按业务对象分组计算间隔
SELECT user_id, login_at,
login_at - LAG(login_at) OVER (PARTITION BY user_id ORDER BY login_at) AS gap
FROM login_logs;参数与行为
| 写法 | 含义 | 边界行为 |
|---|---|---|
| 取值函数无参数 | 取下一行同列的值 | 末行返回空值 |
| 指定偏移量 | 取向后第若干行 | 超出范围返回空值 |
| 指定默认值 | 超出范围时返回该值 | 便于计算时避免空值 |
| 按分区分组 | 每个分组内独立取值 | 分组边界处会出现空值 |
| 时间差函数 | 按秒等单位求差 | PostgreSQL 用时间戳相减再提取 |
末行取值结果为空值,参与算术运算会让整行结果为空。做平均值或求和统计时要么过滤掉这些行,要么用默认值填充,否则统计口径会悄悄少一行。
排序键相同的情况下,相邻关系取决于数据库的实际执行顺序。计算间隔这类对相邻关系敏感的指标时,一定要把主键之类的唯一列作为次级排序键。