hive指定字段插⼊数据_Hiveinsert字段表错位踩坑
1 问题描述
往 Hive 表 insert 数据后,查询时出现个别⾏字段错位,插⼊语句如下:
insert overwrite table A select col1,col2,col3 from table B where dayid = '';
⾸先测试源表数据查询:
select col1,col2,col3 from B
查询来的数据没发现有什么异常;照理说逐字段查出来没问题,再逐字段插⼊应该不会错位。实际上 hive 的 insert 跟想象中传统的 insert 不太⼀样。
2 排查过程
由于不是全表错位,⽽是个别⾏错位,⾸先根据关键字查询 hive 错位那⾏数据,导出⽂本到本地。⾁眼查看发现有部分"乱码"(异常字符:
insert语句字段顺序^M,如果经验丰富⼀眼就能看出这个是 \001,vim 下可以通过组合键 ctrl + a 输出),怀疑是异常字符导
致,通过 linux od 命令查看 16进制编码,如图所⽰:有好⼏个 \001 ,多么眼熟的数字啊 - 这是 hive 默认字段分隔符。
image.png
⼀般 insert A from select B 我们没有关注 A 表的字段分隔符,看到 \001 直觉跟 A 表的字段分隔符有关:
查看 A 的表结构,字段分隔符默认的 \001。存储类型:textfile。
进⼀步分析:textfile 是 hive 默认的存储结构,⾏存储,存储的实际数据结构跟表逻辑结构⼀致。导⼊数据时会直接把数据⽂件拷贝到hdfs上不进⾏处理。源⽂件可以直接通过hadoop fs -cat 查看; 例如 text 字段分隔符: \001 , 换⾏符: \n,表在 hdfs 实际存储的格式为:
v1\001v2\001v3\n
v4\001v5\001v5
猜测字段值缺失错位的根源在于:⽂本中的不可见字符 \001 插⼊到表中,⽽表以 \001 作为字段分隔符,导致查询字段错位。
3 问题定位
再来看这条 SQL:
insert overwrite table A select col1,col2,col3 from table B where dayid = '';
我们可以还原这条 SQL 从插⼊到查询异常的全流程:
查询:select col1,col2,col3 from table B where dayid = ''; 查询出的数据按照 A 表的字段分隔符以及定义的换⾏符拼接起来。
插⼊:由于 A 表是 textfile ,直接把查询的数据 insert (append)到 hdfs 上
查询:由于多余的字段符 \001 被插⼊到 A 表中,查询的时候必然错乱。
4 解决⽅案
⼊库前清洗掉数据中的 \001
修改 A 表的存储格式为 orc 等(不⽤关⼼字段分隔符)
修改 A 表字段分隔符为其他不可见字符
第⼀种⽅式可⾏且更加合理;
第⼆种⽅式可⾏,⼀种补救⽅案,但是 orc 等格式不⽀持 load 操作
第三种⽅式临时解决问题,不能根本上解决问题;
5 后续思考
对 hive 的基础知识了解不⾜,导致问题出现排查速度较慢。
数据源头进⾏必要的数据 ETL 清洗,对字段分隔符的处理必须谨慎。
Hive 表尽可能使⽤ orc parquet 这类存储⽅式,空间占⽤,查询效率相对 textfile 有⼤幅提升,同时可以规避字段分隔符,错位等问题。更深⼊⼀步 了解 hive orc 这类存储⽅式实现原理。