SQL窗口函数是SQL标准中定义的一类特殊函数,它可以在查询结果集的指定窗口范围内对数据进行计算,既保留原数据的所有行,又能实现分组内的排序、聚合、排名等复杂逻辑,非常适合处理日志类按时间或维度分组分析的场景。

日志分析中常见的窗口函数类型
排序类窗口函数
排序类函数可以对分组内的日志按指定规则排序,常用的有ROW_NUMBER()、RANK()、DENSE_RANK(),三者的区别在于处理并列排名时的逻辑不同。
比如我们需要查询每个服务接口的请求日志中,按请求时间排序的前3条慢请求,就可以用ROW_NUMBER()实现:
-- 假设日志表结构为:id, service_name, request_time, response_time, log_date
SELECT
id,
service_name,
request_time,
response_time,
log_date
FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY service_name
ORDER BY response_time DESC
) AS rn
FROM api_request_log
WHERE log_date = '2024-05-20'
) t
WHERE rn <= 3;
聚合类窗口函数
聚合类窗口函数可以在分组内计算累计值、移动平均值等,不需要像普通聚合函数那样用GROUP BY合并行,常用函数有SUM()、AVG()、COUNT()搭配OVER子句使用。
比如统计每个接口每小时的请求累计量,同时保留每条日志的原始信息:
SELECT
id,
service_name,
log_hour,
request_count,
-- 按接口分组,按小时排序计算累计请求量
SUM(request_count) OVER (
PARTITION BY service_name
ORDER BY log_hour
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_request_count
FROM hourly_api_log
WHERE log_date = '2024-05-20';
取值类窗口函数
取值类函数可以获取分组内相邻行的数据,常用的有LAG()和LEAD(),分别用于获取当前行的前N行和后N行的数据,适合分析日志的时间间隔、状态变化等场景。
比如计算同个用户两次请求的时间间隔,排查请求频率异常的问题:
SELECT
user_id,
request_time,
-- 获取同一个用户上一次请求的时间
LAG(request_time) OVER (
PARTITION BY user_id
ORDER BY request_time
) AS last_request_time,
-- 计算时间间隔,单位秒
TIMESTAMPDIFF(SECOND,
LAG(request_time) OVER (PARTITION BY user_id ORDER BY request_time),
request_time
) AS interval_seconds
FROM user_request_log
WHERE log_date = '2024-05-20';
窗口函数使用注意事项
PARTITION BY子句用于指定分组的字段,如果不写则会对全表数据作为一个分组处理ORDER BY子句在排序类和取值类函数中是必填项,在聚合类函数中可选,用于指定窗口内的排序规则- 窗口范围可以通过
ROWS或RANGE子句指定,默认是ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,即从分组第一行到当前行 - 窗口函数不能直接用在
WHERE子句中,需要嵌套一层子查询或者公用表表达式使用
实际日志分析场景示例
假设我们需要分析系统错误日志,找出每个服务模块中连续出现3次及以上错误的日志段,就可以结合ROW_NUMBER()和分组逻辑实现:
WITH error_log_rank AS (
SELECT
*,
-- 按服务分组,错误日志按时间排序
ROW_NUMBER() OVER (PARTITION BY service_name ORDER BY error_time) AS rn1,
-- 按服务分组,错误日志按时间排序,排除非错误日志后排序
ROW_NUMBER() OVER (
PARTITION BY service_name
ORDER BY error_time
) AS rn2
FROM system_error_log
WHERE log_date = '2024-05-20'
)
SELECT
service_name,
error_time,
error_msg,
COUNT(*) OVER (PARTITION BY service_name, (rn1 - rn2)) AS continuous_error_count
FROM error_log_rank
QUALIFY COUNT(*) OVER (PARTITION BY service_name, (rn1 - rn2)) >= 3;
上述逻辑的核心是通过两次排序的差值,把连续的错误日志分到同一个组,再统计每个组的错误数量,从而快速定位连续错误的日志段。
SQL_window_function日志分析数据分组排序统计聚合计算修改时间:2026-06-12 17:00:38