Hive表数据量统计原理和源码分析
Posted 书忆江南
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hive表数据量统计原理和源码分析相关的知识,希望对你有一定的参考价值。
在Hive explain获得执行计划时,经常会看到如下图所示的表数据量统计:
那么这个数据量,Hive是如何统计出来的呢?
一、Data size统计
1.1、Hive源码
在Hive通过Antlr语法解析器获取到SQL的抽象语法树(AST)并生成校验过元数据的逻辑执行计划后,在优化阶段会使用Statistics统计的规则(rule),如下图所示:
在AnnotateWithStatistics这个类中,在对执行计划进行转化(transform)时会调用TableScanStatsRule这个规则,如下图所示:
在TableScanStatsRule匹配规则中,在拿到裁剪后涉及的分区范围(PrunedPartitionList)后,会调用collectStatistics()方法开始正式统计表Statistics信息,如下图所示:
获取到select语句等涉及的列信息后,调用同名的重载方法,如下图所示:
在最终重载的collectStatistics()方法中,会调用getDataSize()方法来统计数据量(当然也有统计行数的函数调用),如下图所示:
可以看到统计数据量的逻辑是先从Hive metastore(存在MySQL中)的parameters信息中拿到raw data size,如果没拿到就还是从metastore中拿total data size信息,再没拿到就直接去统计HDFS目录文件的大小,并且乘以反序列化因子(因为表文件可能被压缩编码和序列化过,实际容量大小比原来小)。
1.2、Hadoop源码
那么Hive是如何去HDFS统计表目录下的文件大小的呢?在getDataSize()函数中,会调用Hadoop HDFS上的方法,如下图所示:
去Hadoop源码看看,可以看到如果是文件就会直接计算文件长度,如果是目录就递归统计,如下图所示:
那么这个length是如何计算出来的?getLen()函数会用到一个length变量,这个变量最终是在这里被设置的:
这样最后就到JDK层面了,会返回字节大小,如下图所示:
二、Num rows统计
上面Hive的collectStatistics()函数中,调用了getNumRows()统计表的行数,可以看到如果没能从Hive metastore中拿到行数信息,那么就采用估算的方式,如下图所示:
在estimateRowSizeFromSchema()函数中,Hive在拿到表的每一列的信息后,会判断该列的字段类型,从而累加该类型的一个字段值所代表的不同容量大小,分为string、varchar、struct、map等可变长类型和int、double、boolean等固定长度类型两种情况,如下图所示:
累加好表的所有列的一个字段值的容量大小,即估算的一行容量大小后,回到一开始的getNumRows()函数,会把统计的表容量大小除以估算的一行数据的容量大小,最终得到估算的行数,如下图所示:
如果这样都没拿到行数统计(比如之前没拿到表容量等),就返回行数是一行。可以看到Hive的统计方法是有较严谨的响应速度(优先从metastore拿)和容错(万一统计不出来)考虑的。
以上是关于Hive表数据量统计原理和源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Spark3.0 Sql 使用HiveTableScanExec 读取Hive orc表源码分析及参数调优