Greenplum 优化CASE - 对齐JOIN字段类型,使用数组代替字符串,降低字符串处理开销,列存降低扫描开销...
标签
PostgreSQL , 数组 , 字符串 , 字符串处理 , JOIN , where , 类型一致性
背景
Greenplum通常被用作OLAP,在一些用户使用过程中,可能因为数据结构设计,SQL问题等原因导致性能不佳,虽然通过增加节点可以解决问题,但是如果能优化的话,可以节约不少硬件资源。
例如
1、对齐JOIN字段类型。如果等值JOIN的字段类型不一致,无法使用HASH JOIN。
2、对齐where条件字段类型。同上,无法使用HASH JOIN,或者索引扫描。
3、使用数组代替字符串,降低字符串处理开销。如果字符串本身需要大量的格式化处理FILTER,那么使用数组的性能会好很多。
4、列存降低扫描开销,统计型的SQL由于涉及的字段有限,使用列存比行存储性能好很多。
例子
1、这个查询耗费230秒。
SELECT col4,count(DISTINCT c.col1) ptnum from tbl1 a INNER JOIN tbl2 b on b.col2=a.id inner join tbl3 t2 on t2.ID <= (length(b.col3) - length(replace(b.col3,',',''))+1) INNER JOIN tbl4 c on replace(replace(Split_part(reverse(Split_part(reverse(Split_part(b.col3,',',cast(t2.id as int))),',',1)),':',1),'{',''),'"','') = c.id INNER JOIN tbl5 s on a.col4=s.id where replace(replace(reverse(Split_part(Split_part(reverse(Split_part(b.col3,',',cast(t2.id as int))),',',1),':',1)),'"',''),'}','') >'0' and c.col1 not in ('xxxxxx') GROUP BY col4;
2、使用explain analyze分析瓶颈
3、问题:
3.1、JOIN类型不一致,导致未使用HASH JOIN。
3.2、有两个表JOIN时产生笛卡尔积来进行不等于的判断,数据量叠加后需要计算几十万亿次。
tbl2.col3字符串格式如下(需要计算几十万亿次)
{"2":"1","10":"1","13":"1","16":"1","21":"1","26":"1","28":"1","30":"1","32":"1","33":"1","34":"1","35":"1","36":"1","37":"1","39":"1","40":"1","99":"2","100":"2","113":"1","61":"1","63":"4","65":"2"}
3.3、使用了行存储,查询时扫描的量较大,并且无法使用向量计算。
优化
1、使用列存代替行存(除nestloop的内表tbl3,继续使用索引FILTER)
create table tmp_tbl1 (like tbl1) WITH (APPENDONLY=true, ORIENTATION=column);
insert into tmp_tbl1 select * from tbl1;
create table tmp_tbl4 (like tbl4) WITH (APPENDONLY=true, ORIENTATION=column);
insert into tmp_tbl4 select * from tbl4;
create table tmp_tbl5 ( like tbl5) WITH (APPENDONLY=true, ORIENTATION=column);
insert into tmp_tbl5 select * from tbl5;
create table tmp_tbl2 (like tbl2) WITH (APPENDONLY=true, ORIENTATION=column) distributed by (col2);
insert into tmp_tbl2 select * from tbl2;
2、使用array代替text
alter table tmp_tbl2 alter column col3 type text[] using (case col3 when '[]' then '{}' else replace(col3,'"','') end)::text[];
修改后的类型、内容如下
digoal=> select col3 from tmp_tbl2 limit 2; col3
------------------------------------------------------------------------------------------------------------------------ {63:1,65:1,70:1,71:1,73:1,75:1,77:1,45:3,78:1,54:2,44:1,80:1,36:1,84:1,96:2} {2:2,10:1,13:1,16:1,30:1,107:1,26:1,28:1,32:1,33:1,34:1,35:1,36:1,37:1,39:1,99:2,100:2,113:1,40:1,57:1,63:2,64:1,65:4}
(2 rows)
3、join 字段保持一致
alter table tmp_tbl2 alter column col2 type int8;
4、将原来的查询SQL修改成如下(字符串处理变成了数组)
(本例也可以使用二维数组,完全规避字符串处理。)
SELECT col4,count(DISTINCT c.col1) ptnum from tmp_tbl1 a INNER JOIN tmp_tbl2 b on b.col2=a.id inner join tbl3 t2 on t2.ID <= array_length(col3,1) -- 更改 INNER JOIN tmp_tbl4 c on split_part(b.col3[cast(t2.id as int)], ':', 1) = c.id INNER JOIN tmp_tbl5 s on a.col4=s.id where split_part(b.col3[cast(t2.id as int)], ':', 2) > '0' and c.col1 not in ('xxxxxx') GROUP BY col4;
执行计划
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Gather Motion 32:1 (slice7; segments: 32) (cost=543258065.87..543259314.50 rows=41621 width=12) -> GroupAggregate (cost=543258065.87..543259314.50 rows=1301 width=12) Group By: a.col4 -> Sort (cost=543258065.87..543258169.93 rows=1301 width=12) Sort Key: a.col4 -> Redistribute Motion 32:32 (slice6; segments: 32) (cost=542355803.38..543254872.50 rows=1301 width=12) Hash Key: a.col4 -> GroupAggregate (cost=542355803.38..543254040.08 rows=1301 width=12) Group By: a.col4 -> Sort (cost=542355803.38..542655042.19 rows=3740486 width=11) Sort Key: a.col4 -> Redistribute Motion 32:32 (slice5; segments: 32) (cost=6247.23..518770960.13 rows=3740486 width=11) Hash Key: c.col1 -> Hash Join (cost=6247.23..516377049.63 rows=3740486 width=11) Hash Cond: split_part(b.col3[t2.id::integer], ':'::text, 1) = c.id::text -> Nested Loop (cost=5494.14..476568597.41 rows=3852199 width=491) Join Filter: split_part(b.col3[t2.id::integer], ':'::text, 2) > '0'::text -> Broadcast Motion 32:32 (slice3; segments: 32) (cost=5494.14..115247.73 rows=277289 width=483) -> Hash Join (cost=5494.14..23742.36 rows=8666 width=483) Hash Cond: b.col2 = a.id -> Seq Scan on tmp_tbl2 b (cost=0.00..14088.89 rows=8666 width=487) -> Hash (cost=4973.86..4973.86 rows=1301 width=12) -> Redistribute Motion 32:32 (slice2; segments: 32) (cost=2280.93..4973.86 rows=1301 width=12) Hash Key: a.id -> Hash Join (cost=2280.93..4141.42 rows=1301 width=12) Hash Cond: s.id = a.col4 -> Append-only Columnar Scan on tmp_tbl5 s (cost=0.00..1220.97 rows=1491 width=4) -> Hash (cost=1760.66..1760.66 rows=1301 width=12) -> Redistribute Motion 32:32 (slice1; segments: 32) (cost=0.00..1760.66 rows=1301 width=12) Hash Key: a.col4 -> Append-only Columnar Scan on tmp_tbl1 a (cost=0.00..928.22 rows=1301 width=12) -> Index Scan using idx_codeid on tbl3 t2 (cost=0.00..23.69 rows=42 width=8) Index Cond: t2.id <= array_length(b.col3, 1) -> Hash (cost=364.69..364.69 rows=972 width=11) -> Broadcast Motion 32:32 (slice4; segments: 32) (cost=0.00..364.69 rows=972 width=11) -> Append-only Columnar Scan on tmp_tbl4 c (cost=0.00..44.26 rows=31 width=11) Filter: col1 <> 'xxxxxx'::text Settings: effective_cache_size=8GB; enable_nestloop=off; gp_statistics_use_fkeys=on Optimizer status: legacy query optimizer
(39 rows)
性能提升
原来SQL响应时间: 230秒
修改后SQL响应时间: < 16秒
小结
瓶颈分析
1、JOIN时不等条件,必须使用笛卡尔的方式逐一判断,所以如果FILTER条件很耗时(CPU),那么性能肯定好不到哪去。
2、原来大量的reverse, split, replace字符串计算,很耗时。刚好落在笛卡尔上,计算数十万亿次。
3、JOIN字段类型不一致。未使用HASH JOIN。
4、分析SQL,未使用列存储。
优化手段
1、array 代替字符串。
2、改写SQL
3、对齐JOIN类型。
4、使用列存储。
5、保留的NESTLOOP JOIN,内表保持行存储,使用索引扫描。(如果是小表,可以使用物化扫描,更快)
6、analyze table;
Greenplum 优化CASE - 对齐JOIN字段类型,使用数组代替字符串,降低字符串处理开销,列存降低扫描开销...相关推荐
- mysql join 索引 无效_ORACLE MYSQL中join 字段类型不同索引失效的情况-阿里云开发者社区...
ORACLE MYSQL中join 字段类型不同索引失效的情况 重庆八怪 2016-12-29 780浏览量 简介: 关于JOIN使用不同类型的字段类型,数据库可能进行隐士转换,MYSQL ORACL ...
- 【js】将json类型的数组或对象转为字符串
代码实现: JSON.stringify(goodsList); 注:该用法多用于数据的传输,如页面于servlet的数据传输不能使用gson的数组直接传输,使用该方法便可解决问题.
- Greenplum 类型一致性使用规范 - 索引条件、JOIN的类型一致性限制
标签 PostgreSQL , Greenplum , 类型一致 , 索引 , inner转换 , join 背景 在查询时,有很多用户会犯浑,发现建立了索引,但是查询偏偏不走索引. 怎么不走索引啊? ...
- oracle字段规则,Oracle的基本操作+Oracle字段类型(zz)
在Oracle关于时间属性的建表 Example: create tablecourses( cidvarchar(20)not null primary key, cnamevarchar(20)n ...
- [译]Effective Kotlin系列之考虑使用原始类型的数组优化性能(五)
翻译说明: 原标题: Effective Kotlin: Consider Arrays with primitives for performance critical processing 原文地 ...
- mysql set类型使用_MySQL的SET字段类型使用方法
MySQL的SET字段类型使用方法 SET是一个字符串对象,可以有零或多个值,其值来自表创建时规定的允许的一列值.指定包括多个SET成员的SET列值时各成员之间用逗号(',')间隔开.这样SET成员值 ...
- 《大话Java性能优化》面向对象及基础类型相关部分
3.1 面向对象及基础类型 3.1.1 采用Clone()方式创建对象 Java语言里面的所有类都默认继承自java.lang.Object类,在java.lang.Object类里面有一个clone ...
- Greenplum优化--SQL调优篇
目录 目录 数据库查询预准备 VACUUM ANALYZE EXPLAIN执行计划 两种聚合方式 关联 重分布 查询优化 explain参数 选择合适分布键 分区表 压缩表 分组扩展 窗口函数 列存储 ...
- Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解
Mysql hash join之classic hash join CHJ过程详解 hash join的历史 优化器里的hash join算法在SQL Server.Oracle.postgress等 ...
最新文章
- Xcode升级到8之后的一些需要我们手动配置的地方
- JS进阶篇--JS数组reduce()方法详解及高级技巧
- cocos2dxFlappyBird开发总结二:开发环境介绍
- python 网页编程_通过Python编程检索网页
- Matchmaker
- Linux Page Cache参数调优在kafka中的应用
- 搭建属于自己的私有链,部署简单的智能合约
- iOS弹窗UIAlertController的使用
- 地温梯度 河南_河南省地热(温泉)分布规律
- socket编程之TCP/UDP
- CherryPy上传文件
- M1芯片CAD如何安装?M1 mac怎么安装AutoCAD?
- Android Studio查看Android源码
- Win10任务栏100%透明怎么设置?Win10任务栏100%透明设置教程
- 深度学习HDR算法总结
- bzoj3332 旧试题 [最大生成树]
- 产品静电ESD测试标准
- python struct pack unpack
- HC05蓝牙模块配对指南(教程)
- of介词短语作定语_OF介词短语在商务英语中的翻译策略
热门文章
- html5清除手机页面缓存文件夹,WebView自动缓存-清除缓存
- python删除重复值所在的行数_python – 在last中删除具有重复值的行
- python中变量名存储在哪里_python – 如何在内部存储和映射变量名称?
- 基于数据库的事务消息解决分布式事务方案
- iOS扩大按钮的点击范围
- mysql 1449 : The user specified as a definer ('root'@'%') does not exist 解决方法
- 大陆居民身份证验证方法(java)
- 获取网址中参数的方式
- JavaScript——以简单的方式理解闭包
- javascript编程风格(粗略笔记)