问题出现:

最近在做mysql数据导入到hive多分区表的工作。在测试时发现hive数据总条数多出源表数据几倍。从mysql查看几条数据与hive对应的数据进行对比,发现mysql一条数据在hive中被加载成多行数据。如下图:

原始description_shop一条数据:

😊😊😊 Bem-vindos a minha loja! 😊😊😊

📢📢 Oferecemos a você os melhores produtos e artigos para sua casa!

🌟🌟 Nossa missão é atender você da melhor maneira, não se esqueça de nos avaliar com 5 estrelas!

🎈🎈 Siga nossa loja e receba um cupom adicional!

💕💕 Boas compras!

hive sql 分区表 insert into values insert数据到hive分区表报错_hive


mysql中取10条数据结果:

hive sql 分区表 insert into values insert数据到hive分区表报错_hive_02


hive中取10条数据结果:

hive sql 分区表 insert into values insert数据到hive分区表报错_mysql_03


问题出现了,mysql中1条数据在hive中被加载成了多行。

有同学第一时间可能想到我的sqoop语句中是否将-m 指定为1,来,下面上测试脚本:

#1.建hive分区表,先将分区表建好
#2.修改需要导入的表和批次
tablename='shopinfo1'
#3.一级分区
locate='test'
#4.二级分区
batch='1'

#5.将mysql数据导入到hdfs中
sqoop import --connect "jdbc:mysql://192.168.0.213:3306/test" --username root --password 111111 --table $tablename --target-dir /user/hive/warehouse/shopinfo1/locate=$locate/batch=$batch --append --fields-terminated-by '\t' -m 1

#6.增加hive分区表及指定数据目录
#7.刷新分区表
hive -e 'ALTER TABLE shopinfo1 ADD PARTITION(locate="'$locate'",batch="'$batch'") LOCATION "'/user/hive/warehouse/shopinfo1/locate=$locate/batch=$batch'";'

很明显,我已经指定了 -m 1,即指定执行MapReduce的个数为1。

解决方案:

1.使用parquet存储方式。
将hive分区表改成以parquet方式存储数据,同时在利用Sqoop导入数据的时候也要指定parquet存储方式
过程:

#5.将mysql数据导入到hdfs中
sqoop import --connect "jdbc:mysql://192.168.0.213:3306/test" --username root --password 111111 --table $tablename --target-dir /user/hive/warehouse/shopinfo1/locate=$locate/batch=$batch --append --fields-terminated-by '\t' -m 1 --as-parquetfile

hive sql 分区表 insert into values insert数据到hive分区表报错_大数据_04


HDFS上数据:

hive sql 分区表 insert into values insert数据到hive分区表报错_大数据_05

2.利用优化参数–direct
sqoop参数中有优化mysql导数速度的关键参数–direct。
该参数的作用是利用直连模式,使用mysqldump加快速度。
但是使用该参数需要注意以下问题:

  • 【WARN manager.DirectMySQLManager: Direct-mode import from MySQL does not support column】direct方式仅仅支持所有的列 有column的话direct就无效了
  • 【Error: java.io.IOException: Cannot run program “mysqldump”: error=2, No such file or directory】 需要把mysqldump复制到从节点:scp /usr/bin/mysqldump cm-slave1:/usr/bin/
  • 使用direct会使得–null-non-string –null-string无效

过程:

#5.将mysql数据导入到hdfs中
sqoop import --connect "jdbc:mysql://192.168.0.213:3306/test" --username root --password 111111 --table $tablename --target-dir /user/hive/warehouse/shopinfo1/locate=$locate/batch=$batch --append --fields-terminated-by '\t' -m 1 --direct

hive sql 分区表 insert into values insert数据到hive分区表报错_数据_06


HDFS上数据:

hive sql 分区表 insert into values insert数据到hive分区表报错_mysql_07

两种方案的MR区别:

1.改用parquet存储方式的MR过程是Map阶段读取了每条数据

hive sql 分区表 insert into values insert数据到hive分区表报错_mysql_08


2.添加–direct参数的MR过程Map阶段一次性读取全部数据

hive sql 分区表 insert into values insert数据到hive分区表报错_hive_09

展示解决后的效果:

1.使用parquet方式

hive sql 分区表 insert into values insert数据到hive分区表报错_大数据_10

2.使用–direct方式

hive sql 分区表 insert into values insert数据到hive分区表报错_数据_11

总结,mysql数据的编码格式是utf8mb4,hive编码格式utf8.不管用parquet存储还是–direct参数优化,都不能将emoji表情数据完整的存储。

如果有同学有更好的处理方式,希望不吝赐教🌹🌹🌹