GPDB总结

1.Analyze

统计数据是描述存储在数据库中的数据的元数据,查询规划器需要最新的统计信息来为查询选择最佳的执行计划。通过执行analyze语句收集和更新统计信息。analyze命令收集的统计信息会保存到系统表pg_class和pg_statistic。

analyze执行时机

1)加载数据后

2)创建索引操作后

3)数据发生明显变更后,如insert/update/delete操作后

4)analyze表上会申请读锁,注意和其他语句不要产生冲突

改进点

说明

analyze部分列

使用analyze...)为选择的列生成统计信息,确保包含用在连接、WHERE子句、SORT子句、GROUP BY子句或者HAVING子句中的列。

analyze部分分区

只在更改过的分区上执行analyze,同时单独执行analyze收集根分区信息。

analyze基表为什么会耗时很长?

对于分区表,会收集所有分区的信息;即使数据没有变化的分区也会重复收集

analyze耗时和列的关系是怎么样的?

每个列都有对应统计信息,列数多导致耗时变长

analyze基表和分别analyze分区表有差别吗?

analyze基表是analyze分区表的合集操作

pg_class表大小信息

列名

说明

relname

table,index,view等名称。

relpages

表占用的页面(32K)数,是查询规划器生成执行计划的输入;通过vacuum和analyze来更新。

reltuples

表的行数,是查询规划器生成执行计划的输入;通过vacuum和analyze来更新。

pg_stats统计信息

列名

说明

schemaname

schema名称

tablename

表名

null_frac

为空的列项所占的比例

attname

表的行数,是查询计划器生成执行计划的输入;通过vacuum和analyze来更新。

avg_width

该列中非null项的平均存储宽度(以字节为单位)

n_distinct

该列中可区分值的数量估计,基于HLL算法进行估算

most_common_vals

该列中最常见值的数组

most_common_freqs

包含most_common_vals数组中值的频率

histogram_bounds

一个值数组,它把列值划分成大约相同尺寸的分组

correlation

相关关系统计信息,Greenplum不计算该信息

2.VACUUM

删除、更新数据记录时,会产生一些空页,在查询的时候扫描这些空页会影响性能,可以使用vacuum来将这些空页标记为删除,只做标记,不会物理删除,不锁表;使用vacuum full会实际删除这些空页释放物理空间。

对于数据库系统的并发控制,PostgreSQL采用MVCC(多版本并发控制)进行处理。这种机制有一个缺点,就是随着时间的推移,数据文件中积累的dead tuples会越来越多。怎么去清理这些dead tuples,这个时候就需要vacuum处理。

PostgreSQL系统的vacuum是一个例行性的维护过程,系统也会在启动服务时启动autovacuum守护进程对此进行维护,当然也有vacuum命令可以让用户进行手动执行vacuum操作。除了清理dead tuples,vacuum还有冻结事务ID的功能,因为现在PostgreSQL的事务ID只支持32位(大概40亿个事务),当事务ID达到最大值后,它会重新从0开始,这时以前的事务都会变成“未来”的事务变得不可见。

下面主要介绍vacuum清理dead tuples的过程。 在清理dead tuples时,系统有两种处理方式:vacuum 和 vacuum full。主要区别在如下:

vacuum

vacuum full

只是把表中的dead tuples进行删除标记,并没有真正物理删除;vacuum过程中,可以正常访问数据表

物理删除表中的dead tuples,释放空间给操作系统;vacuum full过程中,表被锁定,不允许访问

Vacuum过程

vacuum的执行过程主要分为以下三步:

1. 清除dead tuples指向的index tuples

该过程中,vacuum会顺序扫描目标表,并构建一个dead tuples组成的list链表,该list链表会存储在maintenance_work_mem缓存中。然后vacuum根据dead tuples list移除dead tuples指向的index。

2. 移除dead tuples,更新VM和FSM

这里的移除dead tuples只是标记为可重用该空间,并没有真正物理删除。所以vacuum清理表后,表的实际空间并没有减小。dead tuples在做移除标记后,vacuum会重新排列剩余的元组以进行碎片化整理。然后,需要更新目标表的VM(可见性映射文件)和FSM(空闲空间映射文件)。

3. 更新统计信息和相关系统表

最后,需要更新vacuum目标表的统计信息(以适应最新的查询优化)和相关系统表。

Vacuum Full过程

Vacuum Full和Vacuum最大的不同就是,Vacuum Full是物理删除dead tuples,并把释放的空间重新交给操作系统,所以在vacuum full后,表的大小会减小为实际的空间大小。其处理过程和vacuum大不相同,处理步骤如下:

1. vacuum full开始执行时,系统会先对目标创建一个AccessExclusiveLock ,不允许外界再进行访问(为后面拷贝做准备),然后创建一个表结构和目标表相同的新表。

2. 扫描目标表,把表中的live tuples 拷贝到新表中。

3. 删除目标表,在新表上,重新创建索引,更新VM, FSM以及统计信息,相关系统表等。

所以,vacuum full的本质是生成一个新的数据文件,然后把原有表的live tuples存放到该数据文件中。对比vacuum, vacuum full缺点就是在执行期间不能对表进行访问,由于需要往新表中导入live tuples数据,其执行效率也会很慢。优点是执行后,表空间只存放live tuples,没有冗余的dead tuples,在执行查询效率上会有所提高。

AutoVacuum守护进程

由于vacuum是数据库系统的一个例行性维护,所以系统启动后,会开启一个autovacuum守护进程专门对此处理。autovacuum清理进程一般用vacuum而避免使用vacuum full。理由是,vacuum尽管可以保持表的最小尺寸,但是如果表还有继续增长的空间,这么做就意义不大了,特别是对于频繁写入的表。而且vacuum在执行效率上也比vacuum full好。

上面所说的autovacuum进程是一个launcher进程,它不进行vacuum操作,它负责启动vacuum worker进程,然后由vacuum worker进程进行相应的vacuum和analyze操作。

autovacuum进程会在每autovacuum_naptime时间间隔内为数据库启动autovacuum worker进程。然后每个worker进程会检查数据库中的每一个表,在需要时执行vacuum或analyze操作。如果有N个数据库,则每 autovacuum_naptime/N秒将启动一个新worker进程,在同一时间只允许最多autovacuum_max_workers 个worker进程运行,如果有超过autovacuum_max_workers 个数据库需要被处理,下一个数据库将在第一个worker结束后马上被处理。

3.AO表、堆表、复制表的特点与应用场景

堆表

1、堆表,实际上就是PG的堆存储,堆表的所有变更都会产生REDO,可以实现时间点恢复。但是堆表不能实现逻辑增量备份(因为表的任意一个数据块都有可能变更,不方便通过堆存储来记录位点。)。

一个事务结束时,通过clog以及REDO来实现它的可靠性。同时支持通过REDO来构建MIRROR节点实现数据冗余。

AO表

2、AO表,看名字就知道,只追加的存储,删除更新数据时,通过另一个BITMAP文件来标记被删除的行,通过bit以及偏移对齐来判定AO表上的某一行是否被删除。

事务结束时,需要调用FSYNC,记录最后一次写入对应的数据块的偏移。(并且这个数据块即使只有一条记录,下次再发起事务又会重新追加一个数据块)同时发送对应的数据块给MIRROR实现数据冗余。

因此AO表不适合小事务,因为每次事务结束都会FSYNC,同时事务结束后这个数据块即使有空余也不会被复用。(你可以测试一下,AO表单条提交的IO放大很严重)。

虽然如此,AO表非常适合OLAP场景,批量的数据写入,高压缩比,逻辑备份支持增量备份,因此每次记录备份到的偏移量即可。加上每次备份全量的BITMAP删除标记(很小)。

复制表

3、复制表,顾名思义,每个节点上都会存放一份数据,非常适合用来做索引表进行关联查询,可以有效减少数据重分布,降低网络开销。

4.行存与列存

行存:适合频繁更新或者访问大部分字段的场景;

列存:查询列子集时速度更快,减少磁盘IO。列存储更适合压缩,因为他都是相同类型的数据存在一起

行存和列存的原理

1、行存,以行为形式组织存储,一行是一个tuple,存在一起。当需要读取某列时,需要将这列前面的所有列都进行deform,所以访问第一列和访问最后一列的成本实际上是不一样的。

在这篇文档中,有deform的详细介绍。《PostgreSQL 向量化执行插件(瓦片式实现) 10x提速OLAP》

行存小结:

  • 全表扫描要扫描更多的数据块。
  • 压缩比较低。
  • 读取任意列的成本不一样,越靠后的列,成本越高。
  • 不适合向量计算、JIT架构。(简单来说,就是不适合批处理形式的计算)
  • 需要REWRITE表时,需要对全表进行REWRITE,例如加字段有默认值。

2、列存,以列为形式组织存储,每列对应一个或一批文件。读取任一列的成本是一样的,但是如果要读取多列,需要访问多个文件,访问的列越多,开销越大。

列存小结:

  • 压缩比高。
  • 仅仅支持AO存储(后面会将)。
  • 读取任意列的成本是一样的。
  • 非常适合向量计算、JIT架构。对大批量数据的访问和统计,效率更高。
  • 读取很多列时,由于需要访问更多的文件,成本更高。例如查询明细。
  • 需要REWRITE表时,不需要对全表操作,例如加字段有默认值,只是添加字段对应的那个文件。

什么时候选择行存

如果OLTP的需求偏多,例如经常需要查询表的明细(输出很多列),需要更多的更新和删除操作时。可以考虑行存。

什么时候选择列存

如果OLAP的需求偏多,经常需要对数据进行统计时,选择列存。

需要比较高的压缩比时,选择列存。

如果用户有混合需求,可以采用分区表,例如按时间维度的需求分区,近期的数据明细查询多,那就使用行存,对历史的数据统计需求多那就使用列存。

5.查询慢问题解决思路

5.1.特定查询慢

1. 是否数据膨胀导致

SELECT * FROM gp_toolkit.gp_bloat_diag;

如果查出来确实有很大的数据膨胀,则可以考虑将数据膨胀的表进行 "vacuum/vacuum full" 操作

2. 是否统计信息不准

可以通过执行计划看 Broadcast Motion 这个算子里面的 rows 是否很小,如果是的话可以对统计信息不准确的表进行 analyze 操作,手动收集一下统计信息。

analyze 表名;

3. 是否数据倾斜严重?

4. 是否有锁等待

5. 再就是分析执行计划

  • 是否join查询数据重分布导致
  • 是否落盘文件过大导致
  • seq scan扫描耗时

待补充...

5.2.整个实例查询都很慢

1. 查看监控观察实例cpu、内存等负载情况

查看master节点cpu负载是否很高,master节点负载高一般都是写入导致,可以看看写入情况,另外写入是否有优化空间,比如将insert改成copy的形式。

segment节点cpu负载是否很高,segment节点cpu高的话可以看看实例的并发情况,是不是并发很高,可以通过resource queue进行cpu、队列相关的限制给不同业务设置优先级

5.3.性能优化

Greenplum优化总结 - 水木山川 - 博客园

6.其他

gp_max_slices是什么

为了在查询执行期间实现最大的并行度,会将查询计划的工作划分为slices。slice是计划中独立进行处理的部分。查询计划会为每个motion生成slice,motion的每一侧都有一个slice。

mvcc(多版本并发控制)机制

这个有点复杂,需要看看文档:多版本并发控制(MVCC)_zuodaoyong的博客-CSDN博客_多版本并发控制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值