PostgreSQL 多个数组聚合为一维数组加速(array_agg)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
简介:

标签

PostgreSQL , array_agg , arragg


背景

多个数组聚合为一维数组,求PC。业务背景见:

《PostgreSQL APP海量FEED LOG实时质量统计CASE(含percentile_disc)》

由于PostgreSQL内置的聚合函数array_agg支持的数组聚合实际上是将多个数组聚合为多维数组。并不是一维数组。

例如:

postgres=# select array_agg(arr) from (values(array[1,2,3]), (array[4,5,6])) t(arr);  
     array_agg       
-------------------  
 {{1,2,3},{4,5,6}}  
(1 row)  

而实际上我们要的是一维数组的结果

{1,2,3,4,5,6}  

此时需要自定义一个聚合函数

create aggregate arragg (anyarray) (sfunc = array_cat, stype=anyarray, PARALLEL=safe);      

效果如下

postgres=# select arragg(arr) from (values(array[1,2,3]), (array[4,5,6])) t(arr);  
    arragg       
---------------  
 {1,2,3,4,5,6}  
(1 row)  

但是这个新加的聚合用到了array_cat,大量的memcpy导致性能并不好。

array_agg性能对比arragg

聚合100万个元素.

1、array_agg,耗时0.14秒

postgres=# explain (analyze,verbose,timing,costs,buffers) select array_agg(array[1,2,3,4,5,6,7,8,9,10]) from generate_series(1,100000);  
                                                                QUERY PLAN                                                                  
------------------------------------------------------------------------------------------------------------------------------------------  
 Aggregate  (cost=12.50..12.51 rows=1 width=32) (actual time=113.134..113.134 rows=1 loops=1)  
   Output: array_agg('{1,2,3,4,5,6,7,8,9,10}'::integer[])  
   ->  Function Scan on pg_catalog.generate_series  (cost=0.00..10.00 rows=1000 width=0) (actual time=53.585..66.200 rows=100000 loops=1)  
         Output: generate_series  
         Function Call: generate_series(1, 100000)  
 Planning time: 0.064 ms  
 Execution time: 143.075 ms  
(7 rows)  

2、arragg(use array_cat),耗时108.15秒

postgres=# explain (analyze,verbose,timing,costs,buffers) select arragg(array[1,2,3,4,5,6,7,8,9,10]) from generate_series(1,100000);  
                                                                QUERY PLAN                                                                  
------------------------------------------------------------------------------------------------------------------------------------------  
 Aggregate  (cost=12.50..12.51 rows=1 width=32) (actual time=108081.186..108081.186 rows=1 loops=1)  
   Output: arragg('{1,2,3,4,5,6,7,8,9,10}'::integer[])  
   ->  Function Scan on pg_catalog.generate_series  (cost=0.00..10.00 rows=1000 width=0) (actual time=11.121..81.467 rows=100000 loops=1)  
         Output: generate_series  
         Function Call: generate_series(1, 100000)  
 Planning time: 0.148 ms  
 Execution time: 108154.846 ms  
(7 rows)  

3、unnest聚合,耗时0.59秒

postgres=# explain (analyze,verbose,timing,costs,buffers) select array(select unnest(array[1,2,3,4,5,6,7,8,9,10]) from generate_series(1,100000));
                                                                    QUERY PLAN                                                                    
--------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=517.50..517.51 rows=1 width=32) (actual time=520.327..520.327 rows=1 loops=1)
   Output: $0
   InitPlan 1 (returns $0)
     ->  ProjectSet  (cost=0.00..517.50 rows=100000 width=4) (actual time=11.979..223.223 rows=1000000 loops=1)
           Output: unnest('{1,2,3,4,5,6,7,8,9,10}'::integer[])
           ->  Function Scan on pg_catalog.generate_series  (cost=0.00..10.00 rows=1000 width=0) (actual time=11.972..27.014 rows=100000 loops=1)
                 Output: generate_series
                 Function Call: generate_series(1, 100000)
 Planning time: 0.082 ms
 Execution time: 590.976 ms
(10 rows)

小结

array_cat构建的聚合耗时较多,性能优化提升空间明显。

array_agg代码参考:

src/backend/utils/adt/arrayfuncs.c

即使使用unnest再聚合,性能也比array_cat好很多。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
7月前
|
Python
使用array()函数创建数组
使用array()函数创建数组。
146 3
|
7月前
|
JavaScript 前端开发
总结TypeScript 的一些知识点:TypeScript Array(数组)(下)
一个数组的元素可以是另外一个数组,这样就构成了多维数组(Multi-dimensional Array)。
|
23天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
103 67
|
2月前
|
人工智能 前端开发 JavaScript
拿下奇怪的前端报错(一):报错信息是一个看不懂的数字数组Buffer(475) [Uint8Array],让AI大模型帮忙解析
本文介绍了前端开发中遇到的奇怪报错问题,特别是当错误信息不明确时的处理方法。作者分享了自己通过还原代码、试错等方式解决问题的经验,并以一个Vue3+TypeScript项目的构建失败为例,详细解析了如何从错误信息中定位问题,最终通过解读错误信息中的ASCII码找到了具体的错误文件。文章强调了基础知识的重要性,并鼓励读者遇到类似问题时不要慌张,耐心分析。
|
2月前
|
存储 Java
Java“(array) <X> Not Initialized” (数组未初始化)错误解决
在Java中,遇到“(array) &lt;X&gt; Not Initialized”(数组未初始化)错误时,表示数组变量已被声明但尚未初始化。解决方法是在使用数组之前,通过指定数组的大小和类型来初始化数组,例如:`int[] arr = new int[5];` 或 `String[] strArr = new String[10];`。
100 2
|
2月前
|
存储 JavaScript 前端开发
JavaScript Array(数组) 对象
JavaScript Array(数组) 对象
35 3
|
2月前
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
|
3月前
|
Go
Golang语言之数组(array)快速入门篇
这篇文章是关于Go语言中数组的详细教程,包括数组的定义、遍历、注意事项、多维数组的使用以及相关练习题。
52 5
|
4月前
|
Python
PyCharm View as Array 查看数组
PyCharm View as Array 查看数组
123 1
|
5月前
|
索引

相关产品

  • 云原生数据库 PolarDB