订阅更新

SQL 如何计算滚动7日活跃用户和移动平均?

面试问 143 约 2 分钟读完

本文目录
  1. 面试怎么回答
  2. 先补齐连续日期轴
  3. 可加指标可以直接用窗口函数
  4. 滚动 UV 必须重新做集合去重
  5. 窗口边界需要写进名称
  6. 一个典型场景

面试怎么回答

我会先建立连续日期轴,并明确滚动7日是否包含当天。订单数、金额等可加指标先按日聚合,再用窗口 SUM 或 AVG;用户 UV 不能把日 UV 相加,必须对窗口内用户重新去重。小规模可用日期区间 Join 加 COUNT DISTINCT,大规模高频查询可以用 Bitmap 集合并集,允许误差时使用 HLL。最后校验窗口首尾日期、缺失日、时区和未完整数据。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

看板要展示滚动7日活跃用户,有人把最近7天的日 UV 直接相加,结果比真实用户数高出很多。

原因很简单:同一个用户连续活跃7天,被重复算了7次。

滚动窗口的第一步不是写 ROWS BETWEEN,而是先判断指标能否相加,以及窗口到底包含哪些自然日。


先补齐连续日期轴

计算7日移动平均时,ROWS BETWEEN 6 PRECEDING AND CURRENT ROW 表示当前行和前6行,不一定等于7个自然日。

如果某天没有数据,这一行就不存在,窗口可能跨到8天前。因此实际工作中常先生成连续日期表,再把日指标 LEFT JOIN 上来,缺失的可加指标按业务规则补0。

可加指标可以直接用窗口函数

PV、订单数、金额等日级可加指标,可以先按天聚合,再计算最近7行的 SUM 或 AVG。

不过移动平均的分母也要说清楚:是固定除以7,还是只对已有观测日求平均?刚上线不足7天的数据,是展示不完整窗口,还是保持 NULL?这些都属于指标口径。

滚动指标类型对比

滚动 UV 必须重新做集合去重

UV 不是可加指标。小规模场景可以为每个观察日关联 event_date 在前6天到当天之间的活跃明细,再按观察日 COUNT DISTINCT user_id。

这种区间 Join 容易产生数据膨胀。查询频繁或数据量很大时,更适合把每天的用户集合预聚合成 Bitmap,再做7天并集;允许近似误差时,也可以使用可合并的 HLL 类摘要。

滚动UV计算方案

窗口边界需要写进名称

“滚动7日”通常指当天加前6个自然日,但也有人定义为不含当天的前7天。事件时间、业务时区和数据延迟也会改变边界。

如果当天数据尚未完整,实时看板可能同时提供“截至当前小时”和“完整自然日”两套结果,不能把它们直接比较。


一个典型场景

某报表的滚动7日活跃长期等于日 UV 的六七倍。SQL 语法没有报错,任务也每天成功,问题是直接对日 UV 做了 SUM。

抽样一个连续活跃用户后就能发现,他在同一个7日窗口里出现了多次。改为合并用户集合再去重后,指标恢复正常;同时补齐日期轴,避免无数据日期让窗口长度漂移。

窗口函数只能保证行范围,业务还要保证日期范围和指标可加性。

刷题进度保存在当前浏览器