PostgreSQL sharding : citus 系列3 - 窗口函数调用限制 与 破解之法(套用gpdb执行树,分步执行)

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS SQL Server,基础系列 2核4GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
简介: 标签PostgreSQL , citus , 窗口函数背景窗口函数是分析场景常用的,目前(citus 7.5)仅支持两种场景使用window函数,1、partition by 必须是分布键。

标签

PostgreSQL , citus , 窗口函数


背景

窗口函数是分析场景常用的,目前(citus 7.5)仅支持两种场景使用window函数,

1、partition by 必须是分布键。

2、where条件里面带分布键的等值过滤条件。

本质上:目前(citus 7.5)window函数不支持跨shard操作,或者说过程中不进行重分布。

而Greenplum这方面做得很好,是一个完整的MPP数据库。

citus window函数的支持

postgres=# \set VERBOSITY verbose  
  
  
postgres=# select row_number() over(partition by bid order by aid) rn,* from pgbench_accounts;  
ERROR:  0A000: could not run distributed query because the window function that is used cannot be pushed down  
HINT:  Window functions are supported in two ways.   
Either add an equality filter on the distributed tables' partition column   
or   
use the window functions with a PARTITION BY clause containing the distribution column  
LOCATION:  DeferErrorIfQueryNotSupported, multi_logical_planner.c:938  

满足以下条件即可支持

1、partition by 必须是分布键。

2、where条件里面带分布键的等值过滤条件。

postgres=# select row_number() over(partition by bid order by aid) rn,* from pgbench_accounts where aid=1;  
 rn | aid | bid | abalance |                                        filler                                          
----+-----+-----+----------+--------------------------------------------------------------------------------------  
  1 |   1 |   1 |        0 |                                                                                       
(1 row)  
  
postgres=# select row_number() over(partition by aid order by bid) rn,* from pgbench_accounts  limit 1;  
 rn | aid | bid | abalance |                                        filler                                          
----+-----+-----+----------+--------------------------------------------------------------------------------------  
  1 | 298 |   1 |        0 |                                                                                       
(1 row)  

执行计划

postgres=# explain verbose select row_number() over(partition by aid order by bid) rn,* from pgbench_accounts  limit 1;  
                                                                       QUERY PLAN                                                                          
---------------------------------------------------------------------------------------------------------------------------------------------------------  
 Limit  (cost=0.00..0.00 rows=0 width=0)  
   Output: remote_scan.rn, remote_scan.aid, remote_scan.bid, remote_scan.abalance, remote_scan.filler  
   ->  Custom Scan (Citus Real-Time)  (cost=0.00..0.00 rows=0 width=0)  
         Output: remote_scan.rn, remote_scan.aid, remote_scan.bid, remote_scan.abalance, remote_scan.filler  
         Task Count: 128  
         Tasks Shown: One of 128  
         ->  Task  
               Node: host=172.24.211.224 port=1921 dbname=postgres  
               ->  Limit  (cost=705.99..706.01 rows=1 width=105)  
                     Output: (row_number() OVER (?)), pgbench_accounts.aid, pgbench_accounts.bid, pgbench_accounts.abalance, pgbench_accounts.filler  
                     ->  WindowAgg  (cost=705.99..860.95 rows=7748 width=105)  
                           Output: row_number() OVER (?), pgbench_accounts.aid, pgbench_accounts.bid, pgbench_accounts.abalance, pgbench_accounts.filler  
                           ->  Sort  (cost=705.99..725.36 rows=7748 width=97)  
                                 Output: pgbench_accounts.aid, pgbench_accounts.bid, pgbench_accounts.abalance, pgbench_accounts.filler  
                                 Sort Key: pgbench_accounts.aid, pgbench_accounts.bid  
                                 ->  Seq Scan on public.pgbench_accounts_106812 pgbench_accounts  (cost=0.00..205.48 rows=7748 width=97)  
                                       Output: pgbench_accounts.aid, pgbench_accounts.bid, pgbench_accounts.abalance, pgbench_accounts.filler  
(17 rows)  
  
postgres=# explain verbose select row_number() over(partition by bid order by aid) rn,* from pgbench_accounts where aid=1;  
                                                                         QUERY PLAN                                                                            
-------------------------------------------------------------------------------------------------------------------------------------------------------------  
 Custom Scan (Citus Router)  (cost=0.00..0.00 rows=0 width=0)  
   Output: remote_scan.rn, remote_scan.aid, remote_scan.bid, remote_scan.abalance, remote_scan.filler  
   Task Count: 1  
   Tasks Shown: All  
   ->  Task  
         Node: host=172.24.211.232 port=1921 dbname=postgres  
         ->  WindowAgg  (cost=2.51..2.53 rows=1 width=105)  
               Output: row_number() OVER (?), aid, bid, abalance, filler  
               ->  Sort  (cost=2.51..2.51 rows=1 width=97)  
                     Output: aid, bid, abalance, filler  
                     Sort Key: pgbench_accounts.bid  
                     ->  Index Scan using pgbench_accounts_pkey_106819 on public.pgbench_accounts_106819 pgbench_accounts  (cost=0.28..2.50 rows=1 width=97)  
                           Output: aid, bid, abalance, filler  
                           Index Cond: (pgbench_accounts.aid = 1)  
(14 rows)  

Citus未在window调用中支持重分布的过程。

greenplum window函数的支持

支持任意姿势的window调用

postgres=# create table t(id int, c1 int, c2 int);  
NOTICE:  Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'id' as the Greenplum Database data distribution key for this table.  
HINT:  The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew.  
CREATE TABLE  
  
postgres=# insert into t select random()*100000, random()*10, random()*100 from generate_series(1,10000000);  
INSERT 0 10000000  
  
postgres=# explain select row_number() over (partition by c1 order by id) rn,* from t ;  
                                                    QUERY PLAN                                                      
------------------------------------------------------------------------------------------------------------------  
 Gather Motion 33:1  (slice2; segments: 33)  (cost=1477974.88..1553064.94 rows=10012008 width=12)  
   ->  Window  (cost=1477974.88..1553064.94 rows=303395 width=12)  
         Partition By: c1  
         Order By: id  
         ->  Sort  (cost=1477974.88..1503004.90 rows=303395 width=12)  
               Sort Key: c1, id  
               // 以下在citus中用临时表代替  
	       ->  Redistribute Motion 33:33  (slice1; segments: 33)  (cost=0.00..313817.24 rows=303395 width=12)  
                     Hash Key: c1  
                     ->  Seq Scan on t  (cost=0.00..113577.08 rows=303395 width=12)  
 Optimizer status: legacy query optimizer  
(10 rows)  

甚至一个SQL中支持多个不同维度的partition

postgres=# explain select row_number() over (partition by c1 order by id) rn1, row_number() over (partition by c2 order by c1) rn2, * from t ;  
                                                                   QUERY PLAN                                                                     
------------------------------------------------------------------------------------------------------------------------------------------------  
 Gather Motion 33:1  (slice3; segments: 33)  (cost=3017582.83..3192792.97 rows=10012008 width=12)  
   ->  Subquery Scan coplan  (cost=3017582.83..3192792.97 rows=303395 width=12)  
         ->  Window  (cost=3017582.83..3092672.89 rows=303395 width=12)  
               Partition By: coplan.c1  
               Order By: coplan.id  
               ->  Sort  (cost=3017582.83..3042612.85 rows=303395 width=12)  
                     Sort Key: coplan.c1, coplan.id  
                     // 以下在citus中用临时表代替  
		     ->  Redistribute Motion 33:33  (slice2; segments: 33)  (cost=1477974.88..1853425.18 rows=303395 width=12)  
                           Hash Key: coplan.c1  
                           ->  Subquery Scan coplan  (cost=1477974.88..1653185.02 rows=303395 width=12)  
                                 ->  Window  (cost=1477974.88..1553064.94 rows=303395 width=12)  
                                       Partition By: t.c2  
                                       Order By: t.c1  
                                       ->  Sort  (cost=1477974.88..1503004.90 rows=303395 width=12)  
                                             Sort Key: t.c2, t.c1  
                                             // 以下在citus中用临时表代替  
					     ->  Redistribute Motion 33:33  (slice1; segments: 33)  (cost=0.00..313817.24 rows=303395 width=12)  
                                                   Hash Key: t.c2  
                                                   ->  Seq Scan on t  (cost=0.00..113577.08 rows=303395 width=12)  
 Optimizer status: legacy query optimizer  
(19 rows)  

小结

citus 7.5的版本,对窗口函数的支持仅如下条件(二选一,满足即可调用):

本质上:目前(citus 7.5)window函数不支持跨shard操作。

1、partition by 必须是分布键。

2、where条件里面带分布键的等值过滤条件。

还是回到那句话,write in SQL, thinking in mapreduce。懂了这句话的精髓,你才可以使用citus用作分析场景,否则先乖乖的用来做TP为主的业务。

(比如上面不支持的场景,一条SQL拆成多条,最笨的方法,先创建一个临时表(按PARTITION BY分布),然后再跑window函数就支持了,多走几步即可。)

让CITUS支持本身不支持的SQL语法的最愉快的方法:

把结构导入Greenplum,看Greenplum的执行计划,将Redistribute Motion 的部分,在citus里面用临时表实现。 你照这个做,绝对可以让citus跑OLAP很欢快。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
10天前
|
关系型数据库 分布式数据库 数据库
PostgreSQL+Citus分布式数据库
PostgreSQL+Citus分布式数据库
42 15
|
SQL 存储 运维
从Citus深度解密如何基于PostgreSQL做分布式数据库
从源码级别揭秘Citus如何基于PostgreSQL做一款分布式数据库,解决分布式场景的数据分片、分布式SQL、分布式事务、数据倾斜、数据迁移等难点问题,理解分布式领域设计的“取”与“舍”。
1817 3
从Citus深度解密如何基于PostgreSQL做分布式数据库
|
存储 SQL 安全
分布式 PostgreSQL,Citus(11.x) 效用函数
分布式 PostgreSQL,Citus(11.x) 效用函数
697 0
|
SQL 分布式计算 关系型数据库
「PostgreSQL技巧」Citus实时执行程序如何并行化查询
「PostgreSQL技巧」Citus实时执行程序如何并行化查询
|
6月前
|
SQL 关系型数据库 分布式数据库
从Citus深度解密如何基于PostgreSQL做分布式数据库
前言分布式数据库能够解决海量数据存储、超高并发吞吐、大表瓶颈以及复杂计算效率等单机数据库瓶颈难题,当业务体量即将突破单机数据库承载极限和单表过大导致性能、维护问题时,分布式数据库是解决上述问题的高性价比方案。数据库作为分布式改造的最大难点,就是"和使用单机数据库一样使用分布式数据库",这也一直是广大...
2893 0
从Citus深度解密如何基于PostgreSQL做分布式数据库
|
SQL 缓存 关系型数据库
分布式 PostgreSQL,Citus 11.x SQL 参考(中文手册)
分布式 PostgreSQL,Citus 11.x SQL 参考(中文手册)
722 0
|
SQL 关系型数据库 PostgreSQL
Citus 11(分布式 PostgreSQL) 文档贡献与本地运行
Citus 11(分布式 PostgreSQL) 文档贡献与本地运行
205 0
Citus 11(分布式 PostgreSQL) 文档贡献与本地运行
|
SQL 关系型数据库 物联网
Hyperscale (Citus) ,分布式 PostgreSQL 实战指南
Hyperscale (Citus) ,分布式 PostgreSQL 实战指南
325 0
|
关系型数据库 分布式数据库 PolarDB
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
363 0
|
存储 缓存 关系型数据库

相关产品

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