“断点重连后的连续会话”指用户短时间(如≤30分钟)内因网络中断等导致连接断开后重新进入,仍视为同一会话;其实现依赖LAG()计算相邻事件时间差并标记新会话起点,再用SUM()窗口函数累积生成连续会话ID,核心是时间间隔判断而非网络层恢复。

什么是“断点重连后的连续会话”?
这不是标准 SQL 术语,而是业务中常见的一种会话(session)定义:用户在一次浏览行为中,若因网络中断、页面关闭再打开等导致连接断开,但间隔很短(比如 ≤30 分钟),仍应视为同一个会话。窗口函数本身不“感知”断点或重连,它只能基于已有时间序列做排序和分组;真正实现该逻辑,靠的是先用 LAG() 或 LEAD() 算出相邻行为的时间差,再用 SUM() 窗口函数做累积标记——本质是“会话切分”,不是“恢复连接”。
用 LAG() + 时间差判断是否开启新会话
核心思路:对每个用户的事件按时间排序,取上一行的 event_time,计算与当前行的时间差;若差值超过阈值(如 1800 秒),就标记为新会话起点。
-
LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time)必须显式写PARTITION BY user_id,否则跨用户比较会错乱 - 时间差要用
EXTRACT(EPOCH FROM ...)(PostgreSQL)或TIMESTAMPDIFF(SECOND, ...)(MySQL)统一转成秒,避免日期类型直接相减出错 - 首条记录的
LAG()返回NULL,需用COALESCE(..., 'epoch'::timestamptz)或类似方式兜底,否则整个差值列变NULL
SELECT
user_id,
event_time,
COALESCE(
EXTRACT(EPOCH FROM event_time - LAG(event_time) OVER (
PARTITION BY user_id ORDER BY event_time
)),
9999999
) > 1800 AS is_new_session_start
FROM events;用 SUM() 窗口函数生成连续会话 ID
上一步得到布尔标记后,不能直接用 ROW_NUMBER(),因为那只是全局序号;必须用 SUM(is_new_session_start::INT) OVER (PARTITION BY user_id ORDER BY event_time) 来累积——每次遇到 TRUE 就加 1,从而为同一会话内所有行赋予相同编号。
-
is_new_session_start是布尔值,PostgreSQL 中可直接转::INT,MySQL 需写CASE WHEN ... THEN 1 ELSE 0 END -
SUM()的ORDER BY必须和LAG()一致,且不能漏掉PARTITION BY user_id,否则用户间会话 ID 串扰 - 这个
SUM()是“范围累积”,不是聚合,所以不会压缩行数——每行都带自己的会话 ID
SELECT
user_id,
event_time,
SUM(CASE WHEN is_new_session_start THEN 1 ELSE 0 END)
OVER (PARTITION BY user_id ORDER BY event_time) AS session_id
FROM (
SELECT
user_id,
event_time,
COALESCE(
EXTRACT(EPOCH FROM event_time - LAG(event_time) OVER (
PARTITION BY user_id ORDER BY event_time
)),
9999999
) > 1800 AS is_new_session_start
FROM events
) t;注意时区和时间精度带来的偏差
真实日志里 event_time 常来自客户端本地时间或毫秒级时间戳,直接相减可能因时区未归一或毫秒舍入产生误判。例如两个本应属于同一会话的请求,因客户端时钟快了 2 秒、服务端存为秒级,算出来差值变成 32 秒,被错误切分。
- 入库前务必把
event_time统一转为 UTC 并截断到秒(或保留毫秒但全程用毫秒计算) - 阈值建议设为 1800 秒(30 分钟)而非 1799 或 1801——避免边界抖动;若业务真有亚秒级敏感,得换用
GENERATE_SERIES或流处理方案 - 某些数据库(如 BigQuery)对
LAG()的空值处理更严格,IGNORE NULLS不适用,必须靠COALESCE显式补值
会话 ID 的连续性只依赖于排序稳定性和阈值一致性,跟物理连接无关;所谓“断点重连”,最终落在时间间隔判断上,别被术语带偏去查连接池或 TCP 层。

















