标签

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字段类型,使用数组代替字符串,降低字符串处理开销,列存降低扫描开销...相关推荐

  1. mysql join 索引 无效_ORACLE MYSQL中join 字段类型不同索引失效的情况-阿里云开发者社区...

    ORACLE MYSQL中join 字段类型不同索引失效的情况 重庆八怪 2016-12-29 780浏览量 简介: 关于JOIN使用不同类型的字段类型,数据库可能进行隐士转换,MYSQL ORACL ...

  2. 【js】将json类型的数组或对象转为字符串

    代码实现: JSON.stringify(goodsList); 注:该用法多用于数据的传输,如页面于servlet的数据传输不能使用gson的数组直接传输,使用该方法便可解决问题.

  3. Greenplum 类型一致性使用规范 - 索引条件、JOIN的类型一致性限制

    标签 PostgreSQL , Greenplum , 类型一致 , 索引 , inner转换 , join 背景 在查询时,有很多用户会犯浑,发现建立了索引,但是查询偏偏不走索引. 怎么不走索引啊? ...

  4. oracle字段规则,Oracle的基本操作+Oracle字段类型(zz)

    在Oracle关于时间属性的建表 Example: create tablecourses( cidvarchar(20)not null primary key, cnamevarchar(20)n ...

  5. [译]Effective Kotlin系列之考虑使用原始类型的数组优化性能(五)

    翻译说明: 原标题: Effective Kotlin: Consider Arrays with primitives for performance critical processing 原文地 ...

  6. mysql set类型使用_MySQL的SET字段类型使用方法

    MySQL的SET字段类型使用方法 SET是一个字符串对象,可以有零或多个值,其值来自表创建时规定的允许的一列值.指定包括多个SET成员的SET列值时各成员之间用逗号(',')间隔开.这样SET成员值 ...

  7. 《大话Java性能优化》面向对象及基础类型相关部分

    3.1 面向对象及基础类型 3.1.1 采用Clone()方式创建对象 Java语言里面的所有类都默认继承自java.lang.Object类,在java.lang.Object类里面有一个clone ...

  8. Greenplum优化--SQL调优篇

    目录 目录 数据库查询预准备 VACUUM ANALYZE EXPLAIN执行计划 两种聚合方式 关联 重分布 查询优化 explain参数 选择合适分布键 分区表 压缩表 分组扩展 窗口函数 列存储 ...

  9. Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解

    Mysql hash join之classic hash join CHJ过程详解 hash join的历史 优化器里的hash join算法在SQL Server.Oracle.postgress等 ...

最新文章

  1. Python 内建函数
  2. html登录界面设计代码_.NET 5 开发WPF - 美食应用登录UI设计
  3. yarn add webpack webpack-cli 报错
  4. PostMessage和sendMessage传递问题
  5. java链表实现_链表的原理及java实现
  6. Spring Boot完成示例
  7. A20(emmc) 编译环境
  8. shiro整合mybatis数据库
  9. 项目背景怎么描述_培训回顾 |第六届“互联网+”之创业大赛项目计划书撰写
  10. 基于mycat的mysql_MySQL基于Mycat实现读写分离
  11. 云烟成雨,我多想再见你,
  12. Udacity机器学习入门笔记——数据集与问题
  13. 基于语法分析的公式分析器设计
  14. scrapy爬虫数据存入mysql数据库
  15. ECCV2022 论文最全汇总!附下载
  16. C++ 强制类型转换:static_cast、dynamic_cast、const_cast 和 reinterpret_cast
  17. python大漠插件多开_绝地助手_python挪用大漠插件教程04鼠键事宜及基本项目头脑...
  18. 计算机图形学-光栅渲染概述
  19. GNN-CS224W: 3 Node Embeddings
  20. capex与opex的区别

热门文章

  1. c语言中for语句的作用是,c语言中for语句是怎么用的
  2. docker-compose观察实时日志_大数据项目实战之在线教育(03实时需求) - 十一vs十一...
  3. 前端vscode常用插件
  4. centos 6.x 64位 运行32位程序
  5. 简练软考知识点整理-控制成本过程
  6. 线程同步以及yield()、wait()、Notify()、Notifyall()
  7. HTML4和HTML5的区别[转]
  8. kubeadm join时出现错误:[ERROR Port-10250]: Port 10250 is in use [ERROR FileAvailable--etc-kubernetes-pki
  9. Linux文件读写改权限详解
  10. 蓝牙BLE(协议栈、OSAL、蓝牙APP工具)