问题Hiveexecutescount(*)insteadofMR?先说结论:如果表数据插入到表中,count(*)统计的时候,Hive会在where条件执行时执行MR,如果没有where条件,Hive会直接获取值从元数据表metastore.TABLE_PARAMS的numRows字段中获取记录数。创建下表以供验证。验证过程中,发现Hive的无条件count(*)统计有一个bug,下面也会对这个bug现象进行验证。创建测试表createdatabasetestdb;usetestdb;--testhivecreatetabletest(idintcomment'id')comment'testhive'insertintotestvalues('1001');selectcount(*)fromtest;selectcount(*)来自testwhereid>=1001;hive表存储位置表描述信息hdfs生成的数据数据内容从上面两张图可以看出建表后插入了一条记录,表会在metastore.TABLE_PARAMS中记录表信息,使用numRows来记录表的编号,查看表所在的HDFS路径生成一个000000_0的文件,下载下来查看确实是1001。不带where条件执行count(*):查询很快,不通过先生。ExecutiveresultswithoutwhereconditionsExecutewithwhereconditions:查询比较慢,MR没了。可以验证,没有where条件的Hive的执行并没有使用MR,而是直接从元数据中获取表的行数。这也是一种优化。毕竟Hive中存储的大部分数据都是T+1数据。数据写入后一般不会改变。Hive的一个bug在本地创建一个ids.txt文件,通过hadoopfs-put命令上传到表映射路径/user/hive/warehouse/testdb.db/test。创建文件并上传到表路径。下载hdfs文件并查看结果。不带where条件的count(*)结果是错误的,带where条件的是正确的。然后通过Hive去执行带条件和不带条件的查询结果,发现不带where条件的查询结果为1,带where条件的结果为3,说明直接上传文件到路径的方法通过hadoopfs-put将结果,Hive的无条件统计的结果是错误的,同时也证明无条件的count(*)是直接从元数据库中取的,但是用select*查询的结果是正确的。解决方案解决上述问题,可以使用Loaddata命令导入数据,但需要注意以下几点:LOCAL表示从本地文件系统加载,文件会被复制到HDFS。没有LOCAL表示数据从HDFS加载,文件直接移动而不是复制。OVERWRITE表示是否覆盖表中的数据(或指定分区中的数据),没有OVERWRITE则直接APPEND不过滤。如果加载了具有相同文件名的文件,它将自动重命名。loaddata使用loaddata命令上传完数据后,使用无条件count(*)再次统计结果,发现Hive再次进行了MR统计,结果正确。综上所述,当使用insertinto方法向Hive表中插入数据时,元数据会记录插入的次数。为了优化查询,无条件count(*)查询直接检查元数据中记录的numRows字段,导致结果不准确。
