什么是窗口函数
窗口函数也称为OLAP(Online Anallytical Processing)函数,意思是对数据库数据进行实时分析处理。窗口函数就是为了实现OLAP而添加的标准SQL功能。
窗口的概念非常重要,它可以理解为记录集合,窗口函数也就是在满足某种条件的记录集合上执行的特殊函数,对于每条记录都要在此窗口内执行函数,有的函数,随着记录不同,窗口大小都是固定的,这种属于静态窗口;有的函数则相反,不同的记录对应着不同的窗口,这种动态变化的窗口叫滑动窗口。
窗口函数和普通聚合函数也很容易混淆,二者区别如下:
聚合函数是将多条记录聚合为一条;而窗口函数是每条记录都会执行,查询结果并不会改变记录条数,有几条记录执行完还是几条。 普通聚合函数也可以用于窗口函数中,赋予它窗口函数的功能。 原因就在于窗口函数的执行顺序(逻辑上的)是在FROM,JOIN,WHERE,GROUP BY,HAVING之后,在ORDER BY,LIMIT,SELECT DISTINCT之前。它执行时GROUP BY的聚合过程已经完成了,所以不会再产生数据聚合。
窗口函数的简单语法如下
<窗口函数> OVER (partition by <用于分组的列名> order by <用于排序的列名>)
聚类窗口函数
聚和窗口函数和上面提到的专用窗口函数用法完全相同,只需要把聚合函数写在窗口函数的位置即可,但是函数后面括号里面不能为空,需要指定聚合的列名
select *,
sum(成绩) over (order by 学号) as current_sum,
avg(成绩) over (order by 学号) as current_avg,
count(成绩) over (order by 学号) as current_count,
max(成绩) over (order by 学号) as current_max,
min(成绩) over (order by 学号) as current_min
from 班级表
聚合函数作为窗口函数,可以在每一行的数据里直观的看到,截止到本行数据,统计数据是多少(最大值、最小值等)。同时可以看出每一行数据,对整体统计数据的影响。
使用聚类窗口函数求P90
对实时统计数据二次加工,根据页面分组计算一天前 白屏、首屏的最大值、平均值、P90
先计算白屏、首屏的最大值、平均值
SELECT
ROUND( t1.spv / t2.totalPv * 100, 2 ) AS 'pv占比',
ROUND( t1.suv / t2.totalUv * 100, 2 ) AS 'uv占比',
t1.`uri` AS '页面地址',
t1.maxFirstPaint AS '白屏最大值',
ROUND( t1.avgFirstPaint, 2 ) AS '白屏平均值',
t1.maxFirstScreen AS '首屏最大值',
ROUND( t1.avgFirstScreen, 2 ) AS '首屏平均值'
FROM
(
SELECT COALESCE
( page_params_alias, '总数' ) 'uri',
sum( pv ) AS spv,
sum( uv ) AS suv,
max( first_paint ) AS maxFirstPaint,
avg( first_paint ) AS avgFirstPaint,
max( first_screen ) AS maxFirstScreen,
avg( first_screen ) AS avgFirstScreen
FROM
tt_ty_overview_ux
WHERE
TO_DAYS( NOW( ) ) - TO_DAYS( freshen_time ) <= 1
GROUP BY
page_params_alias
) t1 ,
(
SELECT
sum( pv ) AS totalPv,
sum( uv ) AS totalUv
FROM
tt_ty_overview_ux
WHERE
TO_DAYS( NOW( ) ) - TO_DAYS( freshen_time ) <= 1
AND locate( 'oss', HOST ) = 0
) t2
白屏、首屏的P90计算逻辑
- 根据页面地址找出时间范围内的数据,分组排序
select * from (
SELECT
js_error_rate,
page_params_alias,
ROW_NUMBER() OVER ( PARTITION BY page_params_alias ORDER BY js_error_rate ASC ) AS p90
FROM
tt_ty_overview_ux
WHERE
TO_DAYS( NOW( ) ) - TO_DAYS( freshen_time ) <= 1
) t
PARTITION BY子句将结果集划分为分区。 ROW_NUMBER()函数分别应用于每个分区,并重新初始化每个分区的行号。PARTITION BY子句是可选的。如果未指定,ROW_NUMBER()函数会将整个结果集视为单个分区。
· ORDER BY子句定义结果集的每个分区中的行的逻辑顺序。 ORDER BY子句是必需的,因为ROW_NUMBER()函数对顺序敏感。
· OVER()是一个开窗函数,对集合进行聚合计算
- 得到分组总数 * 0.9
select * from (
SELECT
js_error_rate,
page_params_alias,
count(1) over (PARTITION BY page_params_alias) as cn,
ROW_NUMBER() OVER ( PARTITION BY page_params_alias ORDER BY js_error_rate ASC ) AS p90
FROM
tt_ty_overview_ux
WHERE
TO_DAYS( NOW( ) ) - TO_DAYS( freshen_time ) <= 1
AND locate( 'oss', HOST ) = 0
) t
WHERE
t.p90 = ROUND( t.cn * 0.9 )
对比cn和 p90,在分组总行数百分之九十的位置,不整除的话四舍五入。
- 整合最大值、平均值、P90即可。
参考资料 : mysql窗口函数