PostgreSQL\HybridDB for PG 毫秒级多维数据透视 案例分享

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介:

标签

PostgreSQL , 数据透视 , 实时 , 物化 , 预计算 , 多维分析 , 流计算 , 增量合并 , 调度 , HLL


背景

典型的电商类数据透视业务,透视的语料可能会包含一些用户的标签数据:例如包含品牌的ID,销售区域的ID,品牌对应用户的ID,以及若干用户标签字段,时间字段等。

标签可能会按不同的维度进行归类,例如tag1 性别,tag2 年龄段, tag3 兴趣爱好, ...。

业务方较多的需求可能是对自有品牌的用户进行透视,统计不同的销售区域(渠道)、时间段、标签维度下的用户数(一个非常典型的数据透视需求)。

例子

数据结构举例

每天所在区域、销售渠道的活跃用户ID

t1 (    
  uid,       -- 用户ID    
  groupid,   -- 销售渠道、区域ID    
  day        -- 日期    
)    

每个品牌的自有用户,维护增量

t2 (    
  uid,    -- 用户ID    
  pinpai  -- 品牌    
)    

用户标签,维护增量

t3 (    
  uid,    -- 用户ID    
  tag1,   -- 标签1,如兴趣    
  tag2,   -- 标签2,如性别    
  tag3,   -- 标签3,如年龄段    
  ... ,    
)    

透视举例

对某品牌、某销售区域,某标签、某日进行透视。

例如

select     
  '兴趣' as tag,     
  t3.tag1 as tag_value,     
  count(1) as cnt     
from     
  t1,     
  t2,     
  t3     
where     
  t1.uid = t3.uid     
  and t1.uid = t2.uid     
  and t2.pinpai = ?     
  and t1.groupid = ?     
  AND t1.day = '2017-06-25'     
group by t3.tag1     

这类查询的运算量较大,而且分析师可能对不同的维度进行比对分析,因此建议采用预计算的方法进行优化。

预计算优化

预计算需要得到的结果如下:

t_result (    
  day,      -- 日期    
  pinpai,   -- 品牌ID    
  groupid,  -- 渠道、地区、门店ID    
  tag1,     -- 标签类型1    
  tag2,     -- 标签类型2    
  tag3,     -- 标签类型3    
  ...       -- 标签类型n    
  cnt,      -- 用户数    
  uids,     -- 用户ID数组,这个为可选字段,如果不需要知道ID明细,则不需要保存    
  hll_uids  -- 用户HLL估值    
)    

对于GPDB,可以使用列存储,表分区则按day范围一级分区,按pinpai, groupid哈希进行二级分区,数据分布策略选择随机分布,最后针对每个tag?字段建立单独索引。 从而实现快速的检索(甭管数据量多大,单次透视请求的速度应该可以控制在100毫秒以内)。

得到这份结果后,分析师的查询简化如下(前三个条件通过分区过滤数据,最后根据tag?的索引快速得到结果):

select     
  day, pinpai, groupid, 'tag?' as tag, cnt, uids, hll_uids     
from t_result    
where    
  day =     
  and pinpai =     
  and groupid =     
  and tag? = ?      

预计算后,甚至能以非常少量的运算量,实现更加复杂的维度分析,例如分析某两天的差异用户,分析多个TAG叠加的用户等

预计算的方法

产生统计结果的SQL如下

select     
  t1.day,    
  t2.pinpai,    
  t1.groupid,    
  t3.tag1,     
  t3.tag2,    
  t3.tag3,    
  ...    
  count(1) as cnt ,    
  array_agg(uid) as uids,    
  hll_add_agg(hll_hash_integer(uid)) as hll_uids    
from     
  t1,     
  t2,     
  t3     
where     
  t1.uid = t3.uid     
  and t1.uid = t2.uid     
group by     
  t1.day,    
  t2.pinpai,    
  t1.groupid,    
  grouping sets (    
    (t3.tag1),     
    (t3.tag2),    
    (t3.tag3),    
    (...),    
    (t3.tagn)    
  )    

解释:

1、将uid聚合为数组

array_agg(uid)    

2、将UID转换为hll hash val,并聚合为HLL类型

hll_add_agg(hll_hash_integer(uid))    

3、为了按每个标签维度进行统计,可以使用多维分析语法grouping sets,不必写多条SQL来实现,数据也只会扫一遍,将按每个标签维度进行统计

  grouping sets (    
    (t3.tag1),     
    (t3.tag2),    
    (t3.tag3),    
    (...),    
    (t3.tagn)    
  )    

多维分析的语法详见

《PostgreSQL 9.5 new feature - Support GROUPING SETS, CUBE and ROLLUP.》

《Greenplum 最佳实践 - 多维分析的使用(CUBE, ROLLUP, GROUPING SETS in GreenPlum and Oracle)》

预计算结果透视查询

如果进行复杂透视,可以将分析结果的不同记录进行数组的逻辑运算,得到最终UID集合结果。

一、数组逻辑运算

1、在数组1但不在数组2的值

create or replace function arr_miner(anyarray, anyarray) returns anyarray as $$    
  select array(select * from (select unnest($1) except select unnest($2)) t group by 1);    
$$ language sql strict;    

2、数组1和数组2的交集

create or replace function arr_overlap(anyarray, anyarray) returns anyarray as $$    
  select array(select * from (select unnest($1) intersect select unnest($2)) t group by 1);    
$$ language sql strict;    

3、数组1和数组2的并集

create or replace function arr_merge(anyarray, anyarray) returns anyarray as $$      
  select array(select unnest(array_cat($1,$2)) group by 1);    
$$ language sql strict;    

例如在促销活动前(2017-06-24)的用户集合为UID1[],促销活动后(2017-06-25)的用户集合为UID2[],想知道促销活动得到了哪些新增用户。

arr_miner(uid2[], uid1[]) 即可得到。

二、我们使用了HLL类型,HLL本身支持数据的逻辑计算

1、计算唯一值个数

hll_cardinality(users)    

2、计算两个HLL的并集,得到一个HLL

hll_union()    

例如在促销活动前(2017-06-24)的用户集合HLL为uid1_hll,促销活动后(2017-06-25)的用户集合HLL为uid2_hll,想知道促销活动得到了多少新增用户。

hll_cardinality(uid2_hll) - hll_cardinality(uid1_hll)    

预计算调度

业务以前通过即时JOIN得到透视结果,而现在我们使用事先统计的方法得到透视结果,事先统计本身是需要调度的。

调度方法取决于数据的来源,以及数据合并的方法,流式增量或批量增量。

一、数据按天统计,历史统计数据无更新,只有增量。

定时将统计结果写入、合并至t_result结果表。

insert into t_result     
select     
  t1.day,    
  t2.pinpai,    
  t1.groupid,    
  t3.tag1,     
  t3.tag2,    
  t3.tag3,    
  ...    
  count(1) as cnt ,    
  array_agg(uid) as uids ,    
  hll_add_agg(hll_hash_integer(uid)) as hll_uids    
from     
  t1,     
  t2,     
  t3     
where     
  t1.uid = t3.uid     
  and t1.uid = t2.uid     
group by     
  t1.day,    
  t2.pinpai,    
  t1.groupid,    
  grouping sets (    
    (t3.tag1),     
    (t3.tag2),    
    (t3.tag3),    
    (...),    
    (t3.tagn)    
  )    

二、合并统计维度数据

每天的统计结果只有按天统计的结果,如果要查询按月,或者按年的统计,需要对天的数据查询并汇聚。

当然,业务也能选择异步汇聚,最终用户查询汇聚后的结果。

t_result_month (    
  month,    -- yyyy-mm    
  pinpai,   -- 品牌ID    
  groupid,  -- 渠道、地区、门店ID    
  tag1,     -- 标签类型1    
  tag2,     -- 标签类型2    
  tag3,     -- 标签类型3    
  ...       -- 标签类型n    
  cnt,      -- 用户数    
  uids,    -- 用户ID数组,这个为可选字段,如果不需要知道ID明细,则不需要保存    
  hll_uids   -- 用户HLL估值    
)    

array聚合需要自定义一个聚合函数

postgres=# create aggregate arragg (anyarray) ( sfunc=arr_merge, stype=anyarray);    
CREATE AGGREGATE    
postgres=# select arragg(c1) from (values (array[1,2,3]),(array[2,5,6])) t (c1);    
   arragg        
-------------    
 {6,3,2,1,5}    
(1 row)    

按月汇聚SQL如下

select     
  to_char(day, 'yyyy-mm'),    
  pinpai,    
  groupid,    
  tag1,    
  tag2,    
  tag3,    
  ...    
  array_length(arragg(uid),1) as cnt,    
  arragg(uid) as uids,    
  hll_union_agg() as hll_uids    
from t_result    
group by     
  to_char(day, 'yyyy-mm'),    
  pinpai,    
  groupid,    
  tag1,    
  tag2,    
  tag3,    
  ...    

按年汇聚以此类推。

三、流式调度

如果业务方有实时统计的需求,那么可以使用流式计算的方法,实时进行以上聚合统计。方法详见

《流计算风云再起 - PostgreSQL携PipelineDB力挺IoT》

《基于PostgreSQL的流式PipelineDB, 1000万/s实时统计不是梦》

《"物联网"流式处理应用 - 用PostgreSQL实时处理(万亿每天)》

如果数据量非常庞大,可以根据分区键,对数据进行分流,不同的数据落到不同的流计算节点,最后汇总流计算的结果到HybridDB(base on GPDB)中。

《ApsaraDB的左右互搏(PgSQL+HybridDB+OSS) - 解决OLTP+OLAP混合需求》

小结

1、对于透视分析需求,使用倒转的方法,将数据按查询需求进行预计算,得到统计结果,从而在透视时仅需查询计算结果,任意维度透视,都可以做到100毫秒以内的响应速度。

2、使用GROUPING SETS,对多个标签维度进行一次性统计,降低数据重复扫描和重复运算,大幅提升处理效率。

3、使用数组,记录每个透视维度的UID,从而不仅能支持透视,还能支持圈人的需求。同时支持未来更加复杂的透视需求。

4、使用HLL类型,存储估算值,在进行复杂透视时,可以使用HLL,例如多个HLL的值可以UNION,可以求唯一值个数,通常用于评估UV,新增UV等。

5、使用流计算,如果数据需要实时的统计,那么可以使用pipelineDB进行流式分析,实时计算统计结果。(pipelineDB正在插件化,将来使用会更加方便)

6、与阿里云云端组件结合,使用OSS对象存储过渡数据(原始数据),使用OSS_FDW外部表对接OSS,因此过渡数据可以不入库,仅仅用于预计算。大幅降低数据库的写入需求、空间需求。

7、使用Greenplum的一级、二级分区,将透视数据的访问需求打散到更小的单位,然后使用标签索引,再次降低数据搜索的范围,从而做到任意数据量,任意维度透视请求100毫秒以内响应。

8、使用列存储,提升压缩比,节省统计数据的空间占用。

参考

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

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
6月前
|
SQL Oracle 关系型数据库
实时计算 Flink版操作报错之往GREENPLUM 6 写数据,用postgresql-42.2.9.jar 报 ON CONFLICT (uuid) DO UPDATE SET 语法有问题。怎么解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
6月前
|
关系型数据库 PostgreSQL
PostgreSQL排序字段不唯一导致分页查询结果出现重复数据
PostgreSQL排序字段不唯一导致分页查询结果出现重复数据
114 0
|
5月前
|
消息中间件 Java 关系型数据库
实时计算 Flink版操作报错合集之从 PostgreSQL 读取数据并写入 Kafka 时,遇到 "initial slot snapshot too large" 的错误,该怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
1005 0
|
5月前
|
DataWorks 安全 关系型数据库
DataWorks产品使用合集之使用Flink CDC读取PostgreSQL数据时如何指定编码格式
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
3月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
268 0
|
3月前
|
SQL 关系型数据库 HIVE
实时计算 Flink版产品使用问题之如何将PostgreSQL数据实时入库Hive并实现断点续传
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
4月前
|
关系型数据库 分布式数据库 数据库
PolarDB产品使用问题之如何进行PostgreSQL(简称PG)的全量和增量备份管理
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
3月前
|
开发框架 关系型数据库 数据库
在 PostgreSQL 中,解决图片二进制数据,由于bytea_output参数问题导致显示不正常的问题。
在 PostgreSQL 中,解决图片二进制数据,由于bytea_output参数问题导致显示不正常的问题。
|
5月前
|
关系型数据库 5G PostgreSQL
postgreSQL 导出数据、导入
postgreSQL 导出数据、导入
52 1
|
5月前
|
SQL 关系型数据库 PostgreSQL
【sql】PostgreSQL物化视图表使用案例
【sql】PostgreSQL物化视图表使用案例
53 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版