窗口函数是什么
ClickHouse 支持标准窗口函数:OVER (PARTITION BY … ORDER BY … ROWS BETWEEN …) 配合 row_number、rank、dense_rank 以及聚合函数使用,用于排名、同环比与滚动统计。窗口计算发生在结果集上,因此内层查询先做好过滤与聚合能显著降低内存与耗时。lagInFrame 与 leadInFrame 是带帧语义的取前后值函数,与部分数据库的 lag / lead 并不完全等价。
基本信息
| 语法 | func() OVER ([PARTITION BY …] [ORDER BY …] [ROWS BETWEEN …]) |
|---|---|
| 常用函数 | row_number、rank、dense_rank、lagInFrame、leadInFrame、聚合函数 OVER |
| 命名窗口 | WINDOW w AS (PARTITION BY …) 供多个表达式复用 |
| 所属系统 | ClickHouse |
典型使用场景
- 组内排名:每个用户按订单金额排名,取各自前几名
- 同环比:用 lagInFrame 取上一周期数值计算增长率
- 滚动统计:近三个点的移动平均或移动求和
- 去重取一条:用 row_number 按业务键分区取第一条
- 组内占比:先算组内总和,再求每条记录占该组的比例
滚动窗口写法
滚动窗口写法
SELECT
user_id,
ts,
sum(value) OVER ( -- 滚动 3 行求和
PARTITION BY user_id -- 按用户分区
ORDER BY ts -- 分区内按时间排序
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS rolling3
FROM metrics
ORDER BY user_id, ts;子句读法
| 组件 | 作用 | 注意 |
|---|---|---|
| PARTITION BY | 分区键 | 分区过大占用内存多 |
| ORDER BY | 分区内顺序 | 排名与前后取值都依赖它 |
| ROWS BETWEEN | 帧范围 | 不写时默认行为与普通聚合不同 |
| row_number | 组内序号 | 只编号不去重 |
| lagInFrame | 取前一行值 | 帧语义与部分数据库不同 |
窗口函数在结果集上计算,内层查询先过滤与聚合能明显降低内存与耗时,尤其在分区键基数很大的时候。
lagInFrame 与 leadInFrame 的边界帧语义与部分数据库的 lag、lead 不同,涉及首尾行时先用几条样例数据验证结果是否符合预期。
命名窗口(WINDOW 子句)能让多个表达式复用同一套分区与排序定义,既减少重复书写,也避免几处定义不一致导致的隐蔽错误。
窗口函数与 GROUP BY 可以在同一条查询里出现:GROUP BY 先把数据压到分组粒度,OVER 再在这个结果上开窗,混用前先想清楚每一步的粒度。