美文网首页
hive执行select count(*) 返回0,但是sele

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

作者: 程序员的交流电 | 来源:发表于2020-09-11 17:31 被阅读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;
    

    相关文章

      网友评论

          本文标题:hive执行select count(*) 返回0,但是sele

          本文链接:https://www.haomeiwen.com/subject/yazpektx.html