hive执行select count(*) 返回0,但是sele

2020-09-11  本文已影响0人  程序员的交流电

首先说一下,会以下的情况有以上的结果
hive表分区,数据正好在hive分区目录里面,然后执行下面语句

alter table test add partition(dt='2020-01-01');

下面列举4种操作hdfs文件和hive表映射的情况。

1.使用标志的load方式,加载数据到分区
hdfs dfs -rm -r -f /test/data1
hdfs dfs -mkdir /test/data1

drop table dept1;

create external table  dept1(
id int,
name string,
area string
) partitioned by (dt string)
row format delimited fields terminated by ','
location '/test/data1';

# load 相当于一个剪切的功能,并且不用走mr
load data inpath "/test/dept.txt" into table dept1 partition(dt='2020-01-01');

执行select count()和select *
文件权限 rwx
select count(
) 结果非0
select * 正常显示数据

2.使用分区,先创建对应的数据目录,然后使用alter 加载数据
#注意上面的情况以及把文件加载走了,load相当于剪切所以需要重新put文件
hdfs dfs -rm -r -f /test/data2
hdfs dfs -mkdir /test/data2

drop table dept2;
create external table  dept2(
id int,
name string,
area string
) partitioned by (dt string)
row format delimited fields terminated by ','
location '/test/data2';

hdfs dfs -mkdir /test/data2/dt=2020-01-01;
hdfs dfs -cp /test/dept.txt   /test/data2/dt=2020-01-01/

alter table dept2 add partition(dt='2020-01-01');

执行select count()和select *
文件权限 rw
select count(
) 结果为0
select * 正常显示数据

3.创建不分区表,使用load的方式加载数据
hdfs dfs -rm -r -f /test/data3
hdfs dfs -mkdir /test/data3

drop table dept3;
create external table  dept3(
id int,
name string,
area string
)
row format delimited fields terminated by ','
location '/test/data3';

load data inpath "/test/dept.txt"  into table dept3;

执行select count()和select *
文件权限 rwx
select count(
) 结果非0
select * 正常显示数据

4.创建不分区表,直接把数据put到表对应文件夹
hdfs dfs -rm -r -f /test/data4
hdfs dfs -mkdir /test/data4

drop table dept4;
create external table  dept4(
id int,
name string,
area string
)
row format delimited fields terminated by ','
location '/test/data4';

hdfs dfs -cp /test/dept.txt  /test/data4/

执行select count()和select *
文件权限 rw
select count(
) 结果非0
select * 正常显示数据

结论

基于上面的四种情况,在创建分区表的时候,有的人会直接把数据放到对应的分区文件夹下面,然后alter add partition这种加载数据的方式执行select count(*)返回0,没有执行mr任务,是直接读取表级统计信息里面的数据的,不执行mr。

解决办法
  1. 重新创建,使用load正规的方式加载
    2.set hive.compute.query.using.stats=false ;
    这个配置控制是否使用talbe的统计信息
    默认的hive.compute.query.using.stats为true,表示读取表级统计信息里面的数据,设置为false,这样不读取统计数据,执行mr任务。

下面是对hive.compute.query.using.stats的解释
为新创建的表和表分区(例如使用INSERT OVERWRITE语句创建的表)启用表级统计信息的自动收集。该参数不生成列级别的统计信息,例如由CBO生成的统计信息。如果禁用,管理员必须使用ANALYZE table语句为新生成的表和表分区手动生成表级统计信息。
可是为什么在默认值为true的情况下,使用load加载的却任然执行了mr,这一部分应该需要看源码的,目前我还没有找到这一段源码,但是我对比了两个边的统计信息,使用以下的语句查看表的统计信息

desc etended  <tableName>

发现使用alter加载数据和使用load加载数据有区别
下面是使用load加载的截图


image.png

下面是使用alter加载的截图


image.png
这里 alter的desc信息里面有一个COLUME_STATS_ACCURATE的数据,但是使用load加载数据的表却没有,然后我把dept1,使用了下面的语句生成统计信息之后,执行count() 发现也不走mr了,所以,这里可以判断,是否存在COLUME_STATS_ACCURATE将会影响到select count()是否执行mr
analyze table dept1 compute statistics for columns;

得到以上的结论,我们在深入的探究一下,如果我们加载了新的数据放到dept1中,dept1里面的统计信息是否会更新。


image.png

在我重新的将数据放到dept1的另外一个partition里面的之后,在查询count(*),却发现重新走mr进行计算了,
然后desc extended dept1,发现没有了COLUME_STATS_ACCURATE的数据


image.png
由此可以得出一个结论,使用load加载数据之后,会将之前的统计数据COLUME_STATS_ACCURATE,删除掉,防止历史数据影响到正常使用。
得到了这个上面的这个结论,我又想,那之间的使用alter的dept2,是怎么又COLUME_STATS_ACCURATE的数据的呢,所以我重新建了一张表用来验证。

原来一张表在建立之初就是默认使用


image.png
综上得出结论

首先,有数据但count(*)返回0,这个是因为hive.compute.query.using.stats=true导致的,但是并不是hive.compute.query.using.stats=true,所有的表都会count(*)=0,首先是要分为表是否是partition ,当表是分区表,在会自动的有COLUME_STATS_ACCURATE的数据(这里的无论hive.compute.query.using.stats是否是true都会有),然后load数据到具体的分区,COLUME_STATS_ACCURATE的就会消失,但是使用alter加载数据到分区,COLUME_STATS_ACCURATE的数据是不会消失的。
当表不是普通的不分区表,是没有COLUME_STATS_ACCURATE的数据的,这个时候无论使用load或者是alter加载数据,执行count(*)都会走mr的。这也就是为什么dept4同样是使用alter的方式,但是执行count(*)的时候取走mr的原因。但是当执行analyze table 命令之后,也会生成统计信息,在执行count(*)不会走mr的。

hive.compute.query.using.stats之前的版本的默认值是fasle,然后现在是ture,具体从哪个版本我不太清楚。如果设置为true,Hive在执行某些查询时,例如select count(1),只利用元数据存储中保存的状态信息返回结果。 为了收集基本状态信息,需要将hive.stats.autogather属性配置为true。为了收集更多的状态信息,需要运行analyze table查询命令,例如下面的语句收集sales_order_fact表的统计信息。

analyze table dept1 compute statistics for columns;
上一篇下一篇

猜你喜欢

热点阅读