首页/数据/NoSQL 速查/窗口函数与 OVER 子句
ClickHouse56 条

窗口函数与 OVER 子句

ClickHouse 支持标准窗口函数:OVER (PARTITION BY … ORDER BY …) 配合 row_number、rank、lagInFrame/leadInFrame 与聚合函数,用于排名、同环比与滚动计算。

NoSQL 速查数据更新于 2026-10-13

窗口函数是什么

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 再在这个结果上开窗,混用前先想清楚每一步的粒度。

易错点

  • lagInFrame/leadInFrame 与部分数据库的 lag/lead 语义不同,边界帧需按官方说明设置
  • 超大分区上的窗口排序会占用较多内存,尽量让 PARTITION BY 键与数据有序性一致
  • 以为窗口函数会自动过滤空值:组内出现空值时排名结果与预期可能不同
  • 在窗口表达式里再套复杂子查询会让优化器难以下推过滤条件,应先聚合再开窗

数据来源与参考

  • ClickHouse Docs: Window functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌