【经验分享】使用analyze收集统计信息的正确姿势

统计数据是描述存储在数据库中的数据的元数据,查询规划器需要最新的统计信息来为查询选择最佳的执行计划。通过执行analyze语句收集和更新统计信息。最近遇到gp5.x通过analyze收集统计信息慢、集群性能下降的现象。本文将分享统计信息收集的优化过程以及涉及到相关概念。

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-db/gpdb/blob/5.24/src/backend/commands/vacuum.c

2)收集单分区的流程

图9 单表收集

在步骤P4、P5、P6中列的数量会影响收集统计信息的耗时。

源码:https://github.com/greenplum-db/gpdb/blob/5.24/src/backend/commands/analyze.c

3.3 analyze执行时机

1)加载数据后

2)创建索引操作后

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

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

3.4 统计信息的保存

analyze命令收集的统计信息会保存到系统表pg_class和pg_statistic。

1)pg_class表大小信息

列名说明
relnametable, index, view等名称。
relpages表占用的页面(32K)数,是查询规划器生成执行计划的输入;通过vacuum和analyze来更新。
reltuples表的行数,是查询规划器生成执行计划的输入;通过vacuum和analyze来更新。

表4 pg_class

2)pg_stats统计信息

列名说明
schemanameschema名称
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-db/gpdb

https://docs.greenplum.org/5280/ref_guide/system_catalogs/pg_statistic.html

https://gp-docs-cn.github.io/docs/admin_guide/intro/about_statistics.html

https://gp-docs-cn.github.io/docs/best-practices/analyze.html

作者简介

王爱军,中兴通讯系统架构师&敏捷教练

20年来一直工作在一线的老码农,目前就职于中兴通讯。主要工作方向为5G网络管理系统架构,近期在使用和研究Greenplum。

关注微信公众号

VMware 中国研发中心

Greenplum官方技术交流群

扫码添加小助手即可入群,添加时请备注 “GP网站”