Hadoop集群Hive托管表分区数据损坏查询异常求助
这种情况我之前在维护Hive集群时碰到过好几次,结合你的报错和现象来看,核心问题基本是Hive分区元数据和HDFS实际文件系统不同步,咱们一步步来拆解解决:
问题现象复盘
先把你的问题梳理清楚,方便定位:
- 单年份的
count(*)查询(2015/2016/2017)都能正常执行 - 按年份分组查询时报错,提示2015年某个子分区文件不存在:
Error while compiling statement: FAILED: SemanticException java.io.FileNotFoundException: File hdfs://ASIACELLHDP/apps/hive/warehouse/gprod1t_base.db/toll_tkt_hist_old/yr=2015/mn=01/dy=01 does not exist. [ERROR_STATUS] - 查询2015年少量数据(
limit 10)正常,但查询2016年全量数据时也触发相同的文件不存在错误
原因分析
这里的关键矛盾点是:为什么单年份count(*)没问题,但全量查询或分组就报错?
- Hive的
count(*)在开启分区统计的情况下,会直接读取元数据里的统计值,不需要遍历所有文件,所以即使某个子分区文件缺失也不会触发错误; - 而
select *或者分组查询会触发全分区扫描,Hive会根据元数据记录的所有分区路径去HDFS上找文件,一旦元数据里有个路径实际不存在,就会抛出FileNotFoundException; - 至于查2016年全量也报错,大概率是元数据里还关联了那个不存在的2015子分区信息,导致扫描时依然会去访问无效路径。
排查&解决步骤
1. 校验分区元数据与HDFS实际路径
先查看表的所有分区元数据,确认有没有无效的分区记录:
SHOW PARTITIONS tkt_hist;
然后用HDFS命令检查报错的路径是否真的不存在:
hdfs dfs -ls hdfs://ASIACELLHDP/apps/hive/warehouse/gprod1t_base.db/toll_tkt_hist_old/yr=2015/mn=01/
如果确认dy=01这个子分区路径不存在,说明元数据里多了这条无效记录。
2. 修复无效分区
直接删除元数据里的无效分区(因为是托管表,Hive会自动同步HDFS,但这里路径已经不存在,所以只需要删元数据即可):
ALTER TABLE tkt_hist DROP IF EXISTS PARTITION (yr=2015, mn=01, dy=01);
之后执行分区修复命令,让Hive自动同步元数据和HDFS的实际分区:
MSCK REPAIR TABLE tkt_hist;
这个命令会自动做两件事:添加HDFS上存在但元数据里没有的分区,删除元数据里有但HDFS上不存在的分区。
3. 更新统计信息(可选但推荐)
之前单年份count(*)正常可能是依赖了旧的统计数据,建议更新表和分区的统计信息,避免后续查询出现异常:
ANALYZE TABLE tkt_hist COMPUTE STATISTICS; ANALYZE TABLE tkt_hist PARTITION (yr) COMPUTE STATISTICS;
4. 验证修复结果
修复后重新执行之前报错的查询,确认问题解决:
SELECT * FROM tkt_hist WHERE yr=2016; SELECT yr, count(*) FROM tkt_hist GROUP BY yr;
如果还是报错,重复步骤1-3排查其他可能存在的无效分区。
注意事项
对于Hive托管表,永远不要直接在HDFS上手动删除分区文件,一定要通过Hive的ALTER TABLE DROP PARTITION命令操作,否则很容易出现元数据和实际文件不一致的问题。
内容的提问来源于stack exchange,提问作者omer
相关产品推荐
相关产品推荐

