openGauss内核分析(五):统计信息与行数估计(一)
SQL引擎执行查询主要经历了词法语法解析、查询重写、查询规划和计划执行等步骤。其中,在查询规划过程中,为了生成可执行的最优计划,首先要生成路径,而由于路径存在多样性,因此需要对路径进行淘汰选择。目前优化器进行路径的选择主要是基于估算的代价,因此这种优化器也被称为基于代价的优化器(Cost Based Optimization, CBO)。相对于逻辑优化,这种优化方法是物理优化:根据数据的分布(统计信息)情况来对查询执行路径进行评估,从可选的路径中选择一个执行代价最小的路径进行执行,例如是否选择索引SeqScan vs. IndexScan,选择哪个索引,两表关联选择什么样的连接顺序,选择怎样的具体算法等。
在代价估算时,需要使用基表或连接表的行数,而在很多时候,优化器无法获得准确的行数值,因此需要对行数进行估算(Cardinality Estimation),然后再计算代价。
统计信息
统计信息是物理优化的依据,来源于表信息的统计。其中描述基表数据的特征包括唯一值、MCV(Most Common Value)值等,用于行数估算。
Table-Level表级别统计信息,存储在系统表pg_class。
relptuples总元组数:描述表对应的元组数。
relpages总页面数:描述表对应的磁盘页数。
Column-Level列级别统计信息,存储在系统表pg_statistics,也可以使用视图pg_stats查看数据。
Starelid:表的oid。
Staattnum:表属性编号。
stadistinct:用于描述字段里唯一的非 NULL 数据值的数目,一般用于估算集合分组之后的大小,Join结果集大小。
stanullfrac:用于描述当前列中NULL值在总数中的占比。
属性组{stakind1, stanumbers1, stavalues1}构成PG_STATISTIC表的一个卡槽,在PG_STATISTIC表中有5个卡槽。一般情况下,第一个卡槽存储MCV(Most Common Value)信息:描述出现频率大于一定百分比的值的集合,按照出现的频率进行排序,通常用于表征哪些值上出现了倾斜。第二个卡槽存储Histogram直方图信息,描述除了NULL值、MCV值以外的值的分布情况,一般用于估算选择率。
以MCV卡槽为例属性“stakind1”标识卡槽类型为MCV,其中“1”为“STATISTIC_KIND_MCV”的枚举值;属性stanumbers1与属性stavalues1记录MCV的具体内容,其中stavalues1记录key值,stanumbers1记录key对应的频次。
系统表pg_statistics的定义在文件pg_statistic.h中。
#define STATISTIC_KIND_MCV 1
#define STATISTIC_KIND_HISTOGRAM 2
#define STATISTIC_KIND_CORRELATION 3
#define STATISTIC_KIND_MCELEM 4
#define STATISTIC_KIND_DECHIST 5
统计信息通过analyze命令获得。
表tt的oid为40960,有10000行数据占用345个pages页。第1列unique1的分布情况可以从直方图信息获取,直方图有100个区间,并且没有空值和MCV。第16列string4的分布情况可以通过MCV信息获取,这一列有4个distinct值”AAAAxx” ,”HHHHxx” , “OOOOxx” , “VVVVxx” ,4个值的分布频次都有0.25。