1. 问题说明
复现analyze AO表的效率低,实验的软硬件情况如下:
云服务器 | 2核/2GB/50GB SSD/密集计算型ic4 |
操作系统 | CentOS / 8.2 x86_64 (64bit) |
Greenplum5.24 | 逻辑集群,master/standby和3primary/3mirror |
表1实验环境
1.1 创建AO列存分区表
1)建表语句
图1 建表
2)表中记录数
图2 表记录
1.2 耗时和资源占用
1)在基表上执行统计信息收集
图3 耗时统计
2)CPU和IO资源监控
图4 CPU资源消耗
图5 IO资源消耗
通过实验可以观察到在analyze执行期间CPU占用资源较高,同时也产生一定的IO消耗。
2. 改进思路
2.1 analyze部分列和分区
analyze部分列 | 使用analyze table(column, ...)为选择的列生成统计信息,确保包含用在连接、WHERE子句、SORT子句、GROUP BY子句或者HAVING子句中的列。 |
analyze部分分区 | 只在更改过的分区上执行analyze,同时单独执行analyze rootpartition 收集根分区信息。 |
表2 analyze部分信息
2.2实验验证
1)analyze部分列并统计耗时
图6 analyze部分信息命令
2)多次实验的结果
Cn表时analyze列的数量为n,耗时单位为毫秒。analyze的耗时和列数、分区数成类似正比关系。
图7 analyze耗时统计
3. 原理分析
3.1 疑问
analyze基表为什么会耗时很长呢? | 对于分区表,会收集所有分区的信息;即使数据没有变化的分区也会重复收集; |
analyze耗时和列关系是怎么样的? | 每个列都有对应统计信息,列数多导致耗时变长。 |
analyze基表和分别analyze分区表有差别吗? | analyze基表是analyze分区表的合集操作 |
表3 疑问和猜想
3.2 源码分析
核心代码的实现在vacuum.c和analyze.c中,通过对源码的分析验证了4.1的猜想。
1)主流程
图8 主流程
在步骤P3中分区表的数量会影响收集统计信息的耗时。
源码:https://github.com/greenplum-...
2)收集单分区的流程
图9 单表收集
在步骤P4、P5、P6中列的数量会影响收集统计信息的耗时。
源码:https://github.com/greenplum-...
3.3 analyze执行时机
1)加载数据后
2)创建索引操作后
3)数据发生明显变更后,如insert/update/delete操作后
4)analyze表上会申请读锁,注意和其他语句不要产生冲突
3.4 统计信息的保存
analyze命令收集的统计信息会保存到系统表pg_class和pg_statistic。
1)pg_class表大小信息
relname | table, index, view等名称。 |
relpages | 表占用的页面(32K)数,是查询规划器生成执行计划的输入;通过vacuum和analyze来更新。 |
reltuples | 表的行数,是查询规划器生成执行计划的输入;通过vacuum和analyze来更新。 |
表4 pg_class
2)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不计算该信息 |
表5 pg_stats
pg_stats是由pg_statistic系统表扩展而来的系统视图,记录的是每个表每个字段的统计信息,用于规划器做执行计划选择的时候提供参考。
4. 总结
基于Greenplum数据仓库中会涉及比较多的业务表,而如何高效的收集业务表的统计信息是比较关键的维护操作。本文通过对analyze的耗时长进行优化,采用最佳实践的建议,并进行实验验证,同时结合源码进行效率根因的深入分析。对analyze的原理进一步了解,对更好的使用和运维Greenplum数据库提供帮助。
5. 特别提示
在6版本中,analyze已经做了很大的优化,性能有了极大的提升,这主要归功于analyze的实现方式的优化。在4版本中,analyze时会先创建一个临时表,然后扫描analyze的目标表,并通过random()函数来抽取样本数据插入临时表中。之后,再根据临时表中的数据生成最终的统计信息。在5版本中,进行了一定的优化,去除了临时表,直接通过扫描目标表并使用random()函数抽取样本数据,生成最终的统计信息。
而在6版本中,不再需要扫描目标表,而是通过数据抽样的方式来获取样本数据,极大提升了analyze的性能。在6版本之前,analyze的耗时与表尺寸成正相关,而在6版本中,analyze的耗时与表尺寸不再有正相关性,只与统计信息的精度和收集统计信息的字段数量有关。
6. 参考信息
https://github.com/greenplum-...
https://docs.greenplum.org/52...
https://gp-docs-cn.github.io/...
https://gp-docs-cn.github.io/...
作者简介
王爱军,中兴通讯系统架构师&敏捷教练
20年来一直工作在一线的老码农,目前就职于中兴通讯。主要工作方向为5G网络管理系统架构,近期在使用和研究Greenplum。