什么是adb for pg?

答:1.云原生(资源池化,动态升降配)数据仓库,基于postgreSQL内核

2.基于MMP架构存储和计算能力可水平拓展;支持按区间或值分区的分区表

3.支持sql2008语法及OLAP分析聚合函数,支持视图,pl/sql UDF和触发器,部分兼容ORACLE语法

4.支持行和列存储,支持多种索引。支持压缩技术(列式存储下)

5.支持标准数据库隔离级别,支持分布式事物保持数据一致性

6.向量化计算引擎,cascade架构查询优化器 支持复杂sql的高性能分析

adb集群是什么样的?

一个adb的MMP架构集群中,存在多个adb实例,一个实例包括一个协调节点(负责接收客户端连接和查询请求,负责解析执行计划,分配计算)和多个计算节点。

adb数据库的设计规范:

1.对象数量

合适的数据库对象数量(元数据),单个数据库应控制在10万以内,且数据对象包括:表、视图、函数、序列、索引、分区子表、外部表等。

2.数据类型

类型一致性:关联列使用相同数据

+类型,如果不同,adb会动态转为相同类型

类型最小化:例如char类型可使用vachar类型,性能不会提升,但是会节省空间,又比如,int够用,就不必使用bigint

3.存储模型(堆存储、追加优化(AO)存储、行存储、列存储)

选择存储模型的最佳实践:

[1]对于大型事实分区表,评估并优化不同分区的存储选项。比如,不同的分区使用行或列存储

[2]使用列存储,每个列就是一个文件。对于一个有非常多列的表,经常访问使用行存储,不经常则行

[3]在分区级或存储级别上设置存储类型

[4]考虑使用压缩,提高IO性能

堆存储和AO存储

[1]adb默认为堆存储。

[2]如表和分区经常执行(包括并发执行)UPDATE、DELETE、INSERT操作,使用堆存储。

[3]数据很少更新,之后的插入以批处理方式执行,则使用AO存储。对于AO表,可并发批量INSERT,不可并发批量UPDATE、delete。

行存储和列存储

话不多说,都有各自应用场景

压缩

[1]新增分区不继承父表的压缩方式

[2]压缩和排序联合使用,可达到最佳压缩比

[3]建议在实际保存物理数据的那一层设置字段压缩方式 在压缩文件系统上不要使用数据库压缩 adb的压缩级别(有疑问)

分布键

分布策略的最佳实践:

[1]要么明确指定分布字段,要么使用随机分布。不要使用默认。

[2]理想情况下,能够将数据均匀分布到所有段数据库的一个字段为分布键。

[3]不要使用常出现在where字句中的字段

[4]不要使用日期或者时间字段作为分布键

[5]分布键的字段要么基数很大 要么唯一值

[6]一个字段作为分布键不能使数据均匀分布,可选择两个字段作为分布键,不要超过三个,adb pg使用哈希值进行分布,计算哈希也需要时间。

[7]如果两个还是不能均匀分布(差异超过百分之10),使用随机分布。

[8]小表广播移动操作比重分布移动操作效果好

[9]如果两表的分布键相同,字段的数据类型不同,哈希值可能不同,关联时导致动态重分布。

倾斜:包括计算倾斜,数据倾斜

[1]数据倾斜 gp_toolkit.gp_skew_coefficients视图 skccoeff字段表示变异系数,考虑了数据的均值和可变性。值越大,数据倾斜越严重。

[2]计算倾斜:gp_toolkit.gp_skew_idle_fractions视图 计算表扫描时系统空闲的百分比显示数据分布倾斜情况。其中 siffraction字段显示了表扫描时处于空闲的系统的百分比。值越高,计算倾斜越严重,0.1表示倾斜超过百分之10,以此类推。识别计算倾斜,目前主要靠手动,首先查看临时溢出文件,如有计算倾斜,但是没有造成临时溢出文件,不会影响性能。

分区的最佳实践

[1]为大表建立分区,不要为小表建立分区

[2]根据查询条件可以实现分区裁剪时对大表使用分区

[3]优先使用范围分区,其次列表分区

[4]仅当sql查询包含使用不变操作符(比较符)的简单直接约束时,查询优化器才会执行分区裁剪。

[5]通过检查查询的explain计划验证是否执行分区裁剪非常重要

[6]不要使用默认分区。分区不合理,导致溢出而性能不佳

[7]不要用相同的字段既做分区键有做分布键

[8]避免使用多级分区

[9]对于列存储的表,慎用过多的分区 小文件

[10]考虑好并发量和所有并发查询打开和扫描的分区均值

adb调优:(https://help.aliyun.com/document_detail/284581.html)

1.查看数据分布(检查是否数据倾斜)

select gp_segment_id ,count(1) from $table_name group by 1 order by 1;

2.查看运行最耗时的sql

select current_stampment -query_start as runtime,datname,usename,query from pd_stat_activity
where quert != ''
order by runtime desc limit 10;

3.adb的优化器

4.sql优化

(1)where条件优化:将函数处理放在等式右边 ;对于日期类型的字段判断,条件值可直接使用字符串,会自动转换,无需使用类型转换函数 ;对于分区字段,不要对分区字段进行运算。

(2)分区字段的使用,减少每次表扫描涉及的数据量。特别在多个分区表关联时,每个分区表都需要指定分区字段的条件。

(3)表关联 多表关联的时候,不要写inner join的省略形式 可用join;一个sql语句 关联表不要超过10张;几个大小差不多的表做关联时,过滤性强的优先做join;有大 大 小三张表,避免两张大表进行关联,除非过滤性非常强;有大 小 小三张表内联时,优先join两个小表;两张大表关联 关联字段不能有太多重复值;小表left join超大表(数量过亿),把left join改为先inner join 在left join(原因:可提高性能,也能避免adb产生过多临时文件;因为在adb数据库中,对于left join语句,服务器会固定使用右表的记录,构造hash表,然后用hash join的方式实现关联。如果右表过大,会导致hash表需要占用大量的内存,如果内存超出限制,系统会把hash表的内容,写入到文件系统中的临时文件中,如果是inner join系统会自动选择使用小表建立hash表);表通过分布键关联时,不要使用表达式字段的方式进行关联,不然会造成数据重分布。

(4)排序语句 不要在视图中使用order by语句,在视图中排序语句会被忽略;不要对大的结果集使用排序;如果数据达到亿级别,避免使用partition by,union,用group by代替。

(5)聚合查询 聚合查询的group by键尽可能与分布键保持一致,造成数据重分布;当group by多个属性且包含分布键时,应优先将分布键移至第一位,避免数据重分布;检查执行计划聚合计算方式,除非数据排序,hashaggregate性能通常优于groupaggregate(基于排序实现分组)

(6)嵌套子查询 不要超过4层

(7)union union all:union去重(也可用union all +groupby代替) 如非必要使用union all;建议不要union all子句超过5个,如超过可用insert的形式代替。

5.平常写sql注意点:

(1)查看执行计划,看存在的redistributed和broadcast是否合理

(2)union和union all的使用

(3)避免对大表进行update操作,用delete+insert代替

(4)清空表,使用truncate,不要使用无条件的delete,避免vacuum处理

(5)减少嵌套子查询

(6)避免not in ,not exists

(7)避免子查询subplan和大表nestloopjoin(嵌套循环关联,与之相反的是哈希关联)

6.adb (analyticDB for postgreSQL)执行计划

(1)adb采用基于成本的优化器。优化器考虑的因素(自己设计一个优化器,要考虑哪些东西):关联表的行数,是否有索引,字段数据的基数等;还会考虑数据的位置,降低不同segments间的数据传输量。

(2)explain 、explain analyze,若需对DML语句执行explain analyze而不需要影响数据,可将explain analyze置于事务中(begin;explain analyze...;rollback;)

(3)执行计划可以读到哪些信息:sql的的执行计划 估算的代价,explain analyze还可看到:执行sql的总时间(以毫秒为单位);查询节点需要的工作进程个数;每个操作中处理最多行的segment处理的最大行数以及segment的序号;内存使用量;从处理最多行的segment上获得第一行花费的时间及从该segment获得所有行花费的时间(单位毫秒)

(4)解读执行计划:cost(代价):一部分是启动代价估计,即得到第一行的代价,第二部分为总代价。代价为1.0意味着顺序读一个磁盘页。行数(rows)是查询节点输出行数的估计。长度(width)是查询节点输出的所有字节的总长度(单位字节)。注:节点的代价包括了所有子节点的代价。

(5)执行计划中的操作符:扫描操作:堆表顺序扫描:扫描表的所有行;AO扫描:扫描面向行的AO表;AO列扫描-扫描面向列的AO表;索引扫描:遍历B树索引,从表中获取期望的行;bitmap AO行扫描:从索引中获得AO表行的指针,并根据磁盘位置排序;动态扫描:使用分区选择函数选择待扫描的分区。function scan节点包含分区选择函数的名字:gp_partition_expantsion:选择表的所有分区,不会裁剪分区;gp_partition_selection:根据等价表达式选择分区;gp_partition_inversion:根据范围表达式扫描分区。将动态选择的分区传递给result节点,进而传递给sequence节点。

关联操作符:哈希关联-用关联字段做哈希键,对小表建立哈希表,然后扫描大表,哈希表中判断值相等的行;嵌套循环-遍历大数据集,根据其每一行扫描小表,嵌套循环需要广播一个表的数据,对于小表或者使用索引的表性能好,也出现在笛卡尔关联和范围关联;合并关联-对两个数据集排序,然后合并;广播;重分发;收集;

其他操作符

物化:优化器物化子查询,避免重复计算;initplan-仅需要执行一次的子查询,且对外围查询没有依赖;排序;分组;分组/哈希聚合;追加;过滤器;限制;

6.加载数据

(1)insert语句

通过主服务器master分发到某个segment。最慢的方法,不是大量加载数据

(2)copy语句

从外部文件拷贝数据(小于10K )到数据库表中,插入多行,比insert快,通过master分发,不能并行

(3)基于client sdk数据写入

(4)外部表

create external table lacation字句 数据源 ,format定义数据合适的格式便于解析。