您当前的位置: 首页 >  oracle

sqoop --split-by与oracle的rownum结合使用详细总结

蔚1 发布时间:2019-09-10 23:30:40 ,浏览量:4

主要讲解sqoop的运行原理,以及结合oralce的rownum作为拆分字段是所存在的问题,解决方案

1、sqoop的运行过程分析我们先设计一个简单的sqoop脚本

!/bin/sh

kinit -kt /etc/hyperbase1/conf/hyperbase.keytab hbase/tdh1

export JAVA_HOME=/usr/java/latest

export PATH=$JAVA_HOME/bin:$PATH

sqoop import \

--connect jdbc:oracle:thin:@${HSTAHOST}:${HSTAPORT}/${HSTASERVERNAME} \

--username root \

--password root \

--query "SELECT ROWKEY,ID,NAME,ADDRESS FROM (SELECT ROWNUM AS ROWKEY,T.* FROM PERSON T) WHERE \$CONDITIONS " \

--split-by ROWKEY \

--hive-database ods \

--hive-table person \

--target-dir ${HDFSODSPATH}/person\

--delete-target-dir \

--fields-terminated-by '\001' \

-m 4 \

--hive-drop-import-delims \

--null-string '\N' \

--null-non-string '\N' \

--compression-codec org.apache.hadoop.io.compress.BZip2Codec

首先将--query查询的sql语句-m所配置的数量来进行切分,如上配置的map并发任务数为4个,那么sqoop会将查询的sql语句拆分成4个区域。

切分规则按照其中一个关键的参数--split-by 字段名,sqoop建议选取自增的int类型字段或者表的主键作为拆分字段。如果拆分字段的数据类型为int类型,split会获取作为切分字段的最大值和最小值,然后根据-m需要划分的map任务数来划分区域,拆分后的区域分配到不同的map任务,每个map任务在读取数据库中的一行一行的数据值,抽取到HDFS中。

例如:拆分字段的最小值为1,最大值为1000,map任务书为2个,那么会拆分成(1,500),(501,1000)两个区域,分配到两个不同的map任务中执行。

2、 使用oralce的number作为sqoop的拆分字段存在的问题首先oracle的number可以获取oracle的序列号,而且是自增的唯一数字类型字段,原理上是可以用来作为切分字段,但现在如果将map任务设置为多个情况下,会出现的问题就是,数据抽取完成后总数据量与数据源(oracle)是相同的,但是当我们查询数据内容时,会发现存在数据重复和缺失的现象,解释这个现象需要知道sqoop在切分和抽取的过程中,都做了些什么:sqoop运行过程结合具体的数据来进行解析就是:将rownum直接作为拆分字段由上面的数据抽取过程,我们显而易见的可以的出一个结论,直接使用rownum作为切分字段时,分配到每个map任务的执行sql语句,在每次获取的rownum所对应的值的顺序是各不相同的,最终就会导致数据有重复和缺失的现象。

那么现在数据抽取出现错误数据的问题我们应该怎么去解决呢,那么我们现在可以假设,假如我们按照其中的一个字段进行数据排序,保证每次查询的数据都能够保证顺序是一致的,那么是否就能解决这个问题呢?那么我们现在就进行数据抽取测试,来验证我们的假设是否成立

测试1:

首先测试任意的一个字段进行排序,在获取rownum之前,先按照非主键的字段(ID)进行排序,再将rowkey作为切分字段进行数据抽取,将--query的查询语句修改为

--query "SELECT ROWKEY,ID,NAME,ADDRESS FROM (SELECT ROWNUM AS ROWKEY,T.* FROM (SELECT * FROM PERSON ORDER BY ID )T) WHERE \$CONDITIONS " \

那么他的运行过程以及结果是这样的先使用非主键字段排序,在获取rownum测试结果显示并没有正确的获取数据,这个原因是oracle的order by在对数据进行排序的过程中,同一个排序字段的值的顺序仍然不是固定不变的,所以在切分成4个区域获取rownum的过程中,仍然存在rownum取到同一个值小2的现象。

测试2:

order by字段为表的主键字段,在获取rownum之前,先按照主键的字段(ID)进行排序,再将rowkey作为切分字段进行数据抽取,将--query的查询语句修改为

--query "SELECT ROWKEY,ID,NAME,ADDRESS FROM (SELECT ROWNUM AS ROWKEY,T.* FROM (SELECT * FROM PERSON ORDER BY ID )T) WHERE \$CONDITIONS " \

那么测试结果:经过主键排序以后,可以保证了每个map任务每次查询的rowkey可以对应相同的一条数据,然后我们在进行数据抽取,就会发现数据量正确并且查找数据内容也跟源数据库保持一致。先使用主键字段排序,在获取rownum总结--split-by 与oracle的rownum结合使用的过程中,需要注意rownum的获取原理,rownum并非表中的某一列,oracle每次查询的结果顺序不同,那么rownum的获取结果也不相同,在进行拆分区域和sql语句到每个map任务执行时,所查询的数据也会有交叉的部分存在,那么避免这种现象产生的方法:

  1. 将map任务数设置为1,在数据量比较少,并且在抽取效率要求不高的时候可以采取
  2. 在获取rownum之前,先将数据按照主键进行排序,(建议使用)
  3. 表单一主键的情况下,可以将主键字段作为切分字段

阅读全文: http://gitbook.cn/gitchat/activity/5d77aee5d123d702c4c3375c

您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

FtooAtPSkEJwnW-9xkCLqSTRpBKX

关注
打赏
1688896170
查看更多评论

蔚1

暂无认证

  • 4浏览

    0关注

    4645博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.0569s