滑动窗口 分析SQL 实践

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

标签

PostgreSQL , Greenplum , 滑动窗口 , 滑窗 , 窗口语法 , window , frame , 帧


背景

滑动窗口分析是数据分析中比较常见的需求,例如需要分析每一天的最近7天内的UV、PV、sum, count, avg, min, max等。

pic

因为每一条记录的最近7天的数据都不一样,不能直接GROUP BY,而需要使用 帧 的技术,得到当前行最近7行的数据,并进行统计。

使用的是PostgreSQL的窗口语法。

统计分析 - 滑窗SQL实践

1、创建测试表,每条记录代表某个GROUP 下的当前VALUE。

使用滑动分析,得到每条记录最近7条的SUM,COUNT,count(distinct),avg,min,max等。

postgres=# create table t_slide (id int, grp int2, val int, crt_time timestamp);  
CREATE TABLE  

写入测试数据

postgres=# insert into t_slide select generate_series(1,10000000), random()*100, random()*10000, clock_timestamp();  
INSERT 0 10000000  

创建索引

postgres=# create index idx_t_slide_1 on t_slide (grp,crt_time);  
CREATE INDEX  

滑窗查询

postgres=# select *, count(*) over s,   -- 窗口统计  
                     sum(val) over s,   
		     avg(val) over s,   
		     min(val) over s,   
		     max(val) over s   
           from t_slide   
	   window s as (partition by grp order by crt_time rows 6 PRECEDING)  -- 定义窗口(帧)  
limit 100;  
  
    
  id   | grp | val  |          crt_time          | count |  sum  |          avg          | min  | max    
-------+-----+------+----------------------------+-------+-------+-----------------------+------+------  
   188 |   0 |   90 | 2017-11-29 20:03:01.62792  |     1 |    90 |   90.0000000000000000 |   90 |   90  
   437 |   0 | 5981 | 2017-11-29 20:03:01.628205 |     2 |  6071 | 3035.5000000000000000 |   90 | 5981  
   720 |   0 | 6932 | 2017-11-29 20:03:01.628541 |     3 | 13003 | 4334.3333333333333333 |   90 | 6932  
   979 |   0 | 4227 | 2017-11-29 20:03:01.628841 |     4 | 17230 | 4307.5000000000000000 |   90 | 6932  
  1642 |   0 | 2754 | 2017-11-29 20:03:01.629642 |     5 | 19984 | 3996.8000000000000000 |   90 | 6932  
  1917 |   0 | 6376 | 2017-11-29 20:03:01.629954 |     6 | 26360 | 4393.3333333333333333 |   90 | 6932  
  2112 |   0 | 2538 | 2017-11-29 20:03:01.63018  |     7 | 28898 | 4128.2857142857142857 |   90 | 6932  
  2170 |   0 | 7598 | 2017-11-29 20:03:01.630235 |     7 | 36406 | 5200.8571428571428571 | 2538 | 7598  
  2173 |   0 | 7168 | 2017-11-29 20:03:01.630237 |     7 | 37593 | 5370.4285714285714286 | 2538 | 7598  
  2495 |   0 | 1026 | 2017-11-29 20:03:01.630611 |     7 | 31687 | 4526.7142857142857143 | 1026 | 7598  
  2656 |   0 | 2522 | 2017-11-29 20:03:01.630799 |     7 | 29982 | 4283.1428571428571429 | 1026 | 7598  
  2850 |   0 | 5016 | 2017-11-29 20:03:01.631038 |     7 | 32244 | 4606.2857142857142857 | 1026 | 7598  
  2876 |   0 | 6510 | 2017-11-29 20:03:01.631073 |     7 | 32378 | 4625.4285714285714286 | 1026 | 7598  
  3289 |   0 | 9566 | 2017-11-29 20:03:01.631524 |     7 | 39406 | 5629.4285714285714286 | 1026 | 9566  
  3413 |   0 |   86 | 2017-11-29 20:03:01.631665 |     7 | 31894 | 4556.2857142857142857 |   86 | 9566  
  3673 |   0 | 7581 | 2017-11-29 20:03:01.631969 |     7 | 32307 | 4615.2857142857142857 |   86 | 9566  
  3745 |   0 | 6976 | 2017-11-29 20:03:01.632037 |     7 | 38257 | 5465.2857142857142857 |   86 | 9566  
  4435 |   0 | 1981 | 2017-11-29 20:03:01.632848 |     7 | 37716 | 5388.0000000000000000 |   86 | 9566  
  4439 |   0 | 3453 | 2017-11-29 20:03:01.632852 |     7 | 36153 | 5164.7142857142857143 |   86 | 9566  
  4555 |   0 | 9474 | 2017-11-29 20:03:01.632983 |     7 | 39117 | 5588.1428571428571429 |   86 | 9566  
  4689 |   0 | 9176 | 2017-11-29 20:03:01.633119 |     7 | 38727 | 5532.4285714285714286 |   86 | 9474  
  4714 |   0 | 7124 | 2017-11-29 20:03:01.633175 |     7 | 45765 | 6537.8571428571428571 | 1981 | 9474  
  5019 |   0 | 6520 | 2017-11-29 20:03:01.633495 |     7 | 44704 | 6386.2857142857142857 | 1981 | 9474  

执行计划如下

postgres=# explain select *, count(*) over s, sum(val) over s, avg(val) over s, min(val) over s, max(val) over s from t_slide window s as (partition by grp order by crt_time rows 6 PRECEDING) limit 100;  
                                              QUERY PLAN                                                
------------------------------------------------------------------------------------------------------  
 Limit  (cost=0.43..5.91 rows=100 width=74)  
   ->  WindowAgg  (cost=0.43..547641.44 rows=10000000 width=74)  
         ->  Index Scan using idx_t_slide_1 on t_slide  (cost=0.43..272641.44 rows=10000000 width=18)  
(3 rows)  

效率,毫秒级

postgres=# explain (analyze,verbose,timing,costs,buffers,summary) select *, count(*) over s, sum(val) over s, avg(val) over s, min(val) over s, max(val) over s from t_slide window s as (partition by grp order by crt_time rows 6 PRECEDING) limit 100;  
                                                                       QUERY PLAN                                                                          
---------------------------------------------------------------------------------------------------------------------------------------------------------  
 Limit  (cost=0.43..5.91 rows=100 width=74) (actual time=0.038..0.429 rows=100 loops=1)  
   Output: id, grp, val, crt_time, (count(*) OVER (?)), (sum(val) OVER (?)), (avg(val) OVER (?)), (min(val) OVER (?)), (max(val) OVER (?))  
   Buffers: shared hit=74  
   ->  WindowAgg  (cost=0.43..547641.44 rows=10000000 width=74) (actual time=0.037..0.393 rows=100 loops=1)  
         Output: id, grp, val, crt_time, count(*) OVER (?), sum(val) OVER (?), avg(val) OVER (?), min(val) OVER (?), max(val) OVER (?)  
         Buffers: shared hit=74  
         ->  Index Scan using idx_t_slide_1 on public.t_slide  (cost=0.43..272641.44 rows=10000000 width=18) (actual time=0.020..0.176 rows=101 loops=1)  
               Output: id, grp, val, crt_time  
               Buffers: shared hit=74  
 Planning time: 0.115 ms  
 Execution time: 0.498 ms  
(11 rows)  

估值计算 - 滑窗SQL实践

PostgreSQL的估值计算插件

https://github.com/aggregateknowledge/postgresql-hll

通过估值计算插件,可以快速的实现UV统计,结合窗口语法,可以快速实现滑动窗口范围的UV统计。

最近7天的HLL估值类型得到的UV。

how about a sliding window of uniques over the past 6 days?

SELECT date, #hll_union_agg(users) OVER seven_days  
FROM daily_uniques  
WINDOW seven_days AS (ORDER BY date ASC ROWS 6 PRECEDING);  

the number of uniques you saw yesterday that you didn't see today?

SELECT date, (#hll_union_agg(users) OVER two_days) - #users AS lost_uniques  
FROM daily_uniques  
WINDOW two_days AS (ORDER BY date ASC ROWS 1 PRECEDING);  

窗口、帧 语法

帧,指定记录范围,如果只指定了开始,则开始记录到当前记录表示一帧,统计基于这个窗口的话,就是基于这个帧的范围数据进行统计。

窗口,指整个窗口(over partition)范围进行统计。

A window function call represents the application of an aggregate-like function over some portion of
the rows selected by a query.

Unlike non-window aggregate calls, this is not tied to grouping of the
selected rows into a single output row — each row remains separate in the query output.

However the window function has access to all the rows that would be part of the current row's group
according to the grouping specification (PARTITION BY list) of the window function call.

The syntax of a window function call is one of the following:

function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER window_name  
function_name ([expression [, expression ... ]]) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition )  
function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER window_name  
function_name ( * ) [ FILTER ( WHERE filter_clause ) ] OVER ( window_definition )  

where window_definition has the syntax

[ existing_window_name ]  
[ PARTITION BY expression [, ...] ]  
[ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]  
[ frame_clause ]  

and the optional frame_clause can be one of

{ RANGE | ROWS } frame_start  
{ RANGE | ROWS } BETWEEN frame_start AND frame_end  

where frame_start and frame_end can be one of

UNBOUNDED PRECEDING  
value PRECEDING  
CURRENT ROW  
value FOLLOWING  
UNBOUNDED FOLLOWING  

https://www.postgresql.org/docs/10/static/functions-window.html

https://www.postgresql.org/docs/10/static/tutorial-window.html

https://www.postgresql.org/docs/10/static/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
2月前
|
SQL 存储 数据库
SQL实践篇(二):为什么微信用SQLite存储聊天记录
SQL实践篇(二):为什么微信用SQLite存储聊天记录
66 1
|
2月前
|
存储 SQL Web App开发
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
50 2
|
4月前
|
SQL 存储 缓存
四、SQL语句执行过程分析
四、SQL语句执行过程分析
34 0
|
11天前
|
SQL 自然语言处理 数据库
NL2SQL实践系列(2):2024最新模型实战效果(Chat2DB-GLM、书生·浦语2、InternLM2-SQL等)以及工业级案例教学
NL2SQL实践系列(2):2024最新模型实战效果(Chat2DB-GLM、书生·浦语2、InternLM2-SQL等)以及工业级案例教学
NL2SQL实践系列(2):2024最新模型实战效果(Chat2DB-GLM、书生·浦语2、InternLM2-SQL等)以及工业级案例教学
|
14天前
|
SQL 自然语言处理 测试技术
NL2SQL进阶系列(4):ConvAI、DIN-SQL等16个业界开源应用实践详解[Text2SQL]
NL2SQL进阶系列(4):ConvAI、DIN-SQL等16个业界开源应用实践详解[Text2SQL]
NL2SQL进阶系列(4):ConvAI、DIN-SQL等16个业界开源应用实践详解[Text2SQL]
|
18天前
|
SQL 人工智能 自然语言处理
NL2SQL进阶系列(2):DAIL-SQL、DB-GPT开源应用实践详解Text2SQL
NL2SQL进阶系列(2):DAIL-SQL、DB-GPT开源应用实践详解Text2SQL
NL2SQL进阶系列(2):DAIL-SQL、DB-GPT开源应用实践详解Text2SQL
|
18天前
|
SQL 监控 数据库
数据库管理与电脑监控软件:SQL代码优化与实践
本文探讨了如何优化数据库管理和使用电脑监控软件以提升效率。通过SQL代码优化,如使用索引和调整查询语句,能有效提高数据库性能。同时,合理设计数据库结构,如数据表划分和规范化,也能增强管理效率。此外,利用Python脚本自动化收集系统性能数据,并实时提交至网站,可实现对电脑监控的实时性和有效性。这些方法能提升信息系统稳定性和可靠性,满足用户需求。
60 0
|
21天前
|
SQL 数据库 索引
SQL索引失效原因分析与解决方案
SQL索引失效原因分析与解决方案
24 0
|
29天前
|
SQL 关系型数据库 MySQL
【MySQL】慢SQL分析流程
【4月更文挑战第1天】【MySQL】慢SQL分析流程
|
2月前
|
SQL 存储 NoSQL
SQL实践篇(三):什么是Redis
SQL实践篇(三):什么是Redis
25 1