Hive写入Parquet分区表报错,添加LIMIT后异常消失
Hive Insert Overwrite 无LIMIT时报错,加LIMIT后正常的问题排查
最近我在处理Hive数据插入时遇到了一个奇怪的问题:执行全量Insert Overwrite语句时会抛出异常,但给查询加上LIMIT 100后就能正常运行。
问题重现
报错的执行语句:
insert overwrite table stage_dfqp.user_currency partition (dt='2018-05-16') select fuid, fbpid, fgamefsk from stage_dfqp.pb_gamecoins
添加LIMIT后正常执行的语句:
insert overwrite table stage_dfqp.user_currency partition (dt='2018-05-16') select fuid, fbpid, fgamefsk from stage_dfqp.pb_gamecoins limit 100
目标表结构信息
目标表stage_dfqp.user_currency的建表语句如下:
CREATE TABLE `stage_dfqp.user_currency`( `fuid` bigint , `coin_type` string , `coin_num` bigint ) PARTITIONED BY ( `dt` string) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
可能的原因及解决方案
1. 字段映射与类型不匹配
第一眼就发现一个关键问题:目标表的字段是fuid, coin_type, coin_num,但我查询选择的是fuid, fbpid, fgamefsk。这三个字段的类型大概率和目标表的对应字段不兼容。
- 比如
fbpid如果不是字符串类型,写入coin_type(string类型)就会报错;fgamefsk如果无法转成bigint,写入coin_num也会失败。 - 加LIMIT后可能刚好前100条数据的类型能勉强兼容,但全量数据里存在不符合要求的记录,触发了报错。
解决办法:
先查询源表字段类型,再做显式类型转换:
-- 先查看源表字段类型 desc stage_dfqp.pb_gamecoins; -- 执行插入时做类型转换,匹配目标表字段 insert overwrite table stage_dfqp.user_currency partition (dt='2018-05-16') select fuid, cast(fbpid as string) as coin_type, cast(fgamefsk as bigint) as coin_num from stage_dfqp.pb_gamecoins;
2. 源表存在脏数据
源表中可能存在空值、格式错误或者不符合目标表类型的数据,全量扫描时这些脏数据会触发Parquet SerDe的解析失败,而LIMIT 100刚好没扫到这些问题数据。
解决办法:
先校验源表数据,定位脏数据:
-- 检查字段是否为空 select count(*) from stage_dfqp.pb_gamecoins where fuid is null or fbpid is null or fgamefsk is null; -- 检查fbpid能否转为string类型 select fbpid from stage_dfqp.pb_gamecoins where try_cast(fbpid as string) is null; -- 检查fgamefsk能否转为bigint类型 select fgamefsk from stage_dfqp.pb_gamecoins where try_cast(fgamefsk as bigint) is null;
找到脏数据后进行清理(删除或修正),再执行插入操作。
3. 任务资源不足
全量插入需要的内存、CPU资源超过了Hive的默认配置,导致任务崩溃;而LIMIT后数据量小,资源需求低,所以能顺利完成。
解决办法:
执行语句前调整资源参数(根据集群实际情况调整数值):
set mapreduce.map.memory.mb=4096; set mapreduce.reduce.memory.mb=8192; set hive.exec.dynamic.partition.mode=nonstrict; -- 可根据数据量增加reduce数量 set mapreduce.job.reduces=10;
4. Parquet序列化问题
目标表是Parquet格式,全量写入时可能遇到大字段、特殊字符导致的序列化失败,小量数据时不会触发这类问题。
解决办法:
开启Hive的类型安全检查,提前发现问题:
set hive.strict.checks.type.safety=true;
同时可以调整Parquet相关配置,优化写入:
set parquet.compression=SNAPPY; set hive.exec.dynamic.partition=true;
内容的提问来源于stack exchange,提问作者vasili




