Greenplum聚合函数的两种实现:HashAggregate与GroupAggregate
来源:互联网 发布:迷彩服淘宝分类 编辑:程序博客网 时间:2024/05/19 19:14
在Postgresql/Greenplum数据库中,聚合函数有两种实现方式:HashAggregate与GroupAggregate。
我们现在通过一个最简单的sql来分析这两种聚合的区别以及其应用场景。
select count(1) from pg_class group by oid;
一、两种实现算法的比较:
HashAggregate
对于hash聚合来说,数据库会根据group by字段后面的值算出hash值,并根据前面使用的聚合函数在内存中维护对应的列表。如果select后面有两个聚合函数,那么在内存中就会维护两个对应的数据。同样的,有n个聚合函数就会维护n个同样的数组。对于hash算法来说,数组的长度肯定是大于group by的字段的distinct值的个数的,且跟这个值应该呈线性关系,group by后面的值越唯一,使用的内存也就越大。
执行计划如下:
GroupAggregate
对于普通聚合函数,使用group聚合,其原理是先将表中的数据按照group by的字段排序,这样子同一个group by的值就在一起,这样就只需要对排好序的数据进行一次全扫描,就可以得到聚合的结果了。
执行计划如下:
从上面的两个执行计划的cost来说,GroupAggregate 由于需要排序,效率很差,消耗是HashAggregate的7倍。所以在GP里面,对于这种聚合函数的使用,采用的都是HashAggregate。
二、两种实现的内存消耗:
先建立一张测试表,并且往里面insert数据,通过每个字段的数据唯一性不一致,还有聚合函数的个数来观察HashAggregate与GroupAggregate在内存的消耗情况以及实际的计算时间的比较。
1.表结构如下:
2.插入数据,通过random函数,实现每个字段数据的唯一性不一样
表大小为:
3.使用explain analyze来观察实际数据库消耗的内存差异:
以下是底层单个节点来计算的,避免了广播的时间跟内存消耗
HashAggregate
GroupAggregate
通过这种方法,可以看出,消耗的内存跟实际执行时间的比例:
SQL:
explain analyze select sum(col1),sum(col2),sum(col3),sum(col4),sum(col5),sum(col6),sum(col7),sum(col8),sum(col9) from test_group group by id;
9个聚合函数
group by字段
col1
col2
col3
col4
col5
col6
col7
col8
col9
id
HashAggregate
Executor memory
554K
786K
1074K
1715K
2996K
5469K
13691K
21312K
29428K
29476K
时间(ms)
266
272
275
281
296
323
357
359
352
340
GroupAggregate
Executor memory
19623K
19623K
19623K
19623K
19623K
19623K
19623K
19623K
19623K
19615K
时间(ms)
500
533
547
568
589
609
636
652
649
387
SQL:
27个聚合函数
group by字段
col1
col2
col3
col4
col5
col6
col7
col8
col9
id
HashAggregate
Executor memory
514K
1299K
2340K
4405K
8504K
19687K
69947K
93859K
106419K
106876K
时间(ms)
504.91
511.03
523.36
559.85
616.94
937.73
1179.05
1395.56
1391.27
1391.14
GroupAggregate
Executor memory
19687K
19687K
19687K
19687K
19687K
19687K
19687K
19687K
19687K
19687K
时间(ms)
759.58
782.56
802.4
838.07
880.38
939.52
1104.75
1256.92
1365.61
1142
explain analyze select sum(col1),sum(col2),sum(col3),sum(col4),sum(col5),sum(col6),sum(col7),sum(col8),sum(col9),
max(col1),max(col2),max(col3),max(col4),max(col5),max(col6),max(col7),max(col8),max(col9),
avg(col1),avg(col2),avg(col3),avg(col4),avg(col5),avg(col6),avg(col7),avg(col8),avg(col9) from test_group group by id;
可以看出,对于GroupAggregate来说,消耗的内存基本上是恒定的,无论group by哪个字段。当聚合函数较少的时候,速度也相对较慢,但是相对稳定。
HashAggregate在少数聚合函数是表现优异,但是很多聚合函数,性能跟消耗的内存差异很明显。尤其是受group by字段的唯一性很明显,字段count(district)值越大,hash聚合消耗的内存越多,性能下降剧烈。
所以在sql中有大量聚合函数,group by 的字段由相对比较唯一的时候,应该用GroupAggregate,而不能用HashAggregate。
三、在GP4.1出现的SQL报错:
在GP4.1中,之前出现过 有大量聚合函数,并且group by 的字段由相对比较唯一的SQL报错如下:
ERROR: Unexpected internal error: Segment process received signal SIGSEGV
这个sql其实应该就是占用内存太多,进程被操作系统发出信号干掉导致的报错。
查看执行计划,发现是HashAggregate搞得鬼。一般来说,数据库会根据统计信息来选择HashAggregate或者是GroupAggregate,但是有可能统计信息不够详细或者sql太复杂而选错执行计划。
一般遇到这种问题,有两张办法:
1.拆分成多个sql来跑,减少HashAggregate使用的内存.
2.在跑sql之前,先执行enable_hashagg = off;将hash聚合参数关掉。强制不走HashAggregate,建议用这种。
下次如果再遇到这种sql报错,建议采用这种方法改一下脚本试一下。
注:当work_mem不够内存使用时:
当work_mem足够时:
- Greenplum聚合函数的两种实现:HashAggregate与GroupAggregate
- Greenplum聚合函数的两种实现:HashAggregate与GroupAggregate
- HashAggregate, GroupAggregate, hash join
- Strcpy与memcpy两函数的实现
- 用Oracle自定义聚合函数实现字符串连接的聚合
- Oracle自定义聚合函数实现字符串连接的聚合
- Greenplum的Oracle兼容性函数
- GREENPLUM的分布与分区
- GREENPLUM的分布与分区
- 聚合函数与分组
- 聚合函数与分组
- 聚合函数与分组
- 聚合函数与分组
- 聚合函数与分组
- 聚合函数与分组
- strcmp函数的两种实现
- strpbrk函数的两种实现
- 函数指针实现的两种方法
- 737
- 闭锁、同步屏障、信号量详解
- 产品经理必备神器——Axure软件试用评测
- 深入浅出学Spring Data JPA toPredicate Predicate[] p = new Predicate[list.size()]; query.where(cb.and 201
- MySQL170724
- Greenplum聚合函数的两种实现:HashAggregate与GroupAggregate
- 对List集合嵌套了map集合的排序
- HDU 6038 Function 置换群
- 机器学习之逻辑回归算法
- 禁止Html5在手机上屏幕页面缩放
- 欧拉函数表
- Linux系统服务器上安装MySQL
- 二维数组和vector实现dijkstra
- Vue, App与我(六)