BigData-‘基于代价优化’究竟是怎么一回事? (2)

4. 算子代价计算规则是一种死的规则,可定义。而任意中间结果基本信息需要通过原始表基本信息顺着语法树一层一层往上推导得 出。问题转化为:如何计算原始表基本信息以及定义推导规则。

 

很显然,上述过程是思维过程,真正工程实践是反着由下往上一步一步执行,最终得到代价最小的执行路径。现在再把它从一个个 零件组装起来:

 

1. 首先采集原始表基本信息;

2. 再定义每种算子的基数评估规则,即一个数据集经过此算子执行之后基本信息变化规则。这两步完成之后就可以推导出整个执行 计划树上所有中间结果集的数据基本信息;

3. 定义每种算子的执行代价,结合中间结果集的基本信息,此时可以得出任意节点的执行代价;

4. 将给定执行路径上所有算子的代价累加得到整棵语法树的代价;

5. 计算出所有可能语法树代价,并选出一条代价最小的。

 

CBO基本实现思路

 

上文从理论层面分析了CBO的实现思路,将完整的CBO功能拆分为了多个子功能,接下来聊聊对每一个子功能的实现。

 

第一步,采集原始表基本信息

 

这个操作是CBO最基础的一项工作,采集的主要信息包括表级别指标和列级别指标,如下所示,estimatedSize和rowCount为表级 别信息,basicStats和Histograms为列级别信息,后者粒度更细,对优化更加重要。

 

estimatedSize: 每个LogicalPlan节点输出数据大小(解压)

rowCount: 每个LogicalPlan节点输出数据总条数

basicStats: 基本列信息,包括列类型、Max、Min、number of nulls, number of distinct values, max column length, average column length等

Histograms: Histograms of columns, i.e., equi-width histogram (for numeric and string types) and equi-height histogram (only for numeric types).

 

这里有两个问题值得思考:

 

1. 为什么要采集这些信息?每个对象在优化过程中起到什么作用?

2. 实际工程一般是如何实现这些数据采集的?

 

为什么要采集这些信息?很显然,estimatedSize和rowCount这两个值是算子代价评估的直观体现,这两个值越大,给定算子执行 代价必然越大,所以这两个值后续会用来评估实际算子的执行代价。那basicStats和Histograms这俩用来干啥呢,要不忘初心,之 所以采集原始表的这些信息,是为了顺着执行语法树往上一层一层推导出所有中间结果的基本信息,这俩就是来干这个的,至于怎 么实现的,下一小节会举个例子解释。

 

实际工程如何实现这些数据采集?一般有两种比较可行的方案:打开所有表扫描一遍,这样最简单,而且统计信息准确,缺点是对 于大表来说代价比较大;针对一些大表,扫描一遍代价太大,可以采用采样(sample)的方式统计计算。

 

支持CBO的系统都有命令对原始数据信息进行统计,比如Hive的Analyze命令、Impala的Compute命令、Greenplum的Analyze 命令等,但是需要注意这些命令并不是随时都应该执行的,首先在表数据没有大变动的情况下没必要执行,其次在系统查询高发期 也不应该执行。这里有个最佳实践:尽可能在业务低峰期对表数据有较大变动的表单独执行统计命令,这句话有三个重点,不知道 你看出来没有?

 

第二部,定义核心算子的基数推导规则

 

规则推导意思是说在当前子节点统计信息的基础上,计算父节点相关统计信息的一套推导规则。对于不同算子,推导规则必然不一 样,比如fliter、group by、limit等等的评估推导是不同的。这里以filter为例进行讲解。先来看看这样一个SQL:select * from A , C where  A.id = C.c_id and C.c_id > N ,经过RBO之后的语法树如下图所示:

BigData-‘基于代价优化’究竟是怎么一回事?

问题定义为:假如现在已经知道表C的基本统计信息(estimatedSize、rowCount、basicStats以及histograms),那么如何推导 出经过C.c_id>N过滤后中间结果的基本统计信息呢?让我们来看看:

 

1. 假设已知C列的最小值c_id.Min、最大值c_id.Max以及总行数c_id.Distinct,同时假设数据分布均匀,如下图所示:

BigData-‘基于代价优化’究竟是怎么一回事?

 

2. 现在分别有三种情况需要说明,其一是N小于c_id.Min,其二是N大于c_id.Max,其三是N介于c_id.Min和c_id.Max之间。前两 种场景是第三种场景的特殊情况,这里简单的针对第三种场景说明。如下图所示:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfzfz.html