Hive 动态分区剪裁原理
1 介绍
当一个大表和小表进行join,大表的join列是分区列,小表的join列不是分区列时,Hive的动态分区剪裁就会收集小表的join列的集合,发送给tez am, am在为大表计算split时,会根据集合的值过滤大表不需要扫描的分区,从而减少数据扫描量,提高sql执行性能。
2 使用
针对hive 3.1.0版本,有如下参数与动态分区剪裁有关
参数名 |
默认值 |
描述 |
hive.tez.dynamic.partition.pruning |
true |
是否开启动态分区剪裁 |
hive.tez.dynamic.partition.pruning.extended |
true |
|
hive.tez.dynamic.partition.pruning.max.event.size |
1*1024*1024L |
AppMasterEventOperator在运行时发送给AM的数量最大值。单位字节。 |
hive.tez.dynamic.partition.pruning.max.data.size |
100*1024*1024L |
Hive在编译过程中估计的AppMasterEventOperator处理数据量最大值。单位字节。 |
对于TPC-DS query6, 开启动态分区剪裁后,query6的执行时间由115s降到了58s ,性能提升1.98倍。
3 原理
3.1 逻辑优化
3.1.1 Join谓词合成
动态分区剪裁在逻辑优化的PredicatePushDown规则前增加了SyntheticJoinPredicate规则,该规则会为每个join的父节点生成一个合成的条件。
如上图,SynthicJoinPredicate会为每个join operator生成两个父Filter Operator, Filter的谓词条件为a in (select b from other table)。
为了能够表达动态列表的表达式,Hive中引入了ExprNodeDynamicListDesc类,该类有三个参数:数据类型、数据源Operator,数据源的列表达式。
对于inner join,在join的所有父节点都会生成谓词,对于left join和right join,只会在右和左侧的父节点生成谓词。
3.1.2 谓词下推
在这一步会借助已有的PredicatePushDown逻辑将谓词条件尽可能的下推到TableScanOperator。
3.2 物理优化
3.2.1 动态分区裁剪优化(DynamicPartitionPruningOptimization)
在遍历Operator树时,当遇到了符合条件的FilterOperator会执行动态分区剪裁优化。条件为: FilterOperator的父节点为TableScanOperator。否则将会把FilterOperator生成的合成谓词替换为常量谓词TRUE。
遇到符合条件的FilterOperator,动态分区剪裁优化会执行以下操作:
1. 收集谓词中所有的动态分区条件的列(a in select b from other table),遍历所有的列并执行2、3。
2. 如果列是分区列,那么生成AppMasterEventOperator,从ReduceSinkOperator的节点开始,收集相关列的集合并将其发送给AppMaster。
3. 将Filter中动态分区谓词条件设置为TRUE
4. 将TableScanOperator动态分区谓词条件设置为TRUE。
随后的优化中会移除谓词为TRUE的filter和表达式。
3.2.2 依据统计量移除动态裁剪
这个优化会先遍历整个Operator树,找到AppMasterEventOperator,如果AppMasterEventOperator的统计数据大于hive.tez.dynamic.partition.pruning.max.data.size参数指定的大小,就会将本分支移除。
3.2.3 动态裁剪循环分析优化
该优化借助Tarjan算法计算图的所有强连通分量。在连通分量中保留处理数据量最小的AppMasterEventOperator.
3.3 Tez 生成task
在这一步,处理所有的AppMasterEventOperator,设置AppMasterEventDesc的目标顶点信息。在运行时,AppMasterEventOperator会将数据发送给设置的顶点。
4 Tez运行时分区剪裁
4.1 AppMasterEventOperator运行时发送分区数据
AppMasterEventOperator在运行时,将会把所有的数据存储到一个buffer中,如果发现数据大小超过了hive.tez.dynamic.partition.pruning.max.event.size指定的大小,那么会重新初始化buffer,只写入两个字段:列名和跳过分区,否则通过ProcessorContext将事件发送给AppMaster。
4.2 HiveSplitGenerator
HiveSplitGenerator用于Tez生成split,其在初始化时会等待事件输入(AppMasterEventOperator发送的事件),如果没有事件会直接跳过动态分区剪裁,如果存在事件,那么会等待所有的事件接收完毕,执行分区剪裁。生成的split中会去除不需要的分区。
5 参考文档
1. https://issues.apache.org/jira/browse/HIVE-7826
2. https://cwiki.apache.org/confluence/display/Hive/MapJoin+and+Partition+Pruning
- 点赞
- 收藏
- 关注作者
评论(0)