sqoop import将Oracle数据加载至hive,数据量变少,只能导入一个mapper的数据量

sqoop脚本如下:

bash 复制代码
sqoop import -D mapred.job.queue.name=highway \
-D mapreduce.map.memory.mb=4096 \
-D mapreduce.map.java.opts=-Xmx3072m \
--connect "jdbc:oracle:thin:@//1.2.3.4.5:61521/LZY2" \
--username root \
--password '123456' \
--query "SELECT 
ZBDM
,ZBMC
,TO_CHAR(TJSJ, 'YYYY') AS tjsj_year
,TO_CHAR(TJSJ, 'MM') AS tjsj_month
,TO_CHAR(TJSJ, 'DD') AS tjsj_day
,TO_CHAR(TJSJ, 'YYYY-MM-DD HH24:MI:SS') AS TJSJ
......
,TO_CHAR(INPUTTIME, 'YYYY-MM-DD HH24:MI:SS') AS INPUTTIME
,UUID
,TO_CHAR(INSERTTIME, 'YYYY-MM-DD HH24:MI:SS') AS INSERTTIME
FROM LZJHGX.T_JSZX_TF_KJ2_LL
WHERE TO_CHAR(TJSJ , 'YYYY-MM-DD') < TO_CHAR(SYSDATE,'YYYY-MM-DD') AND \$CONDITIONS" \
--split-by ROWNUM \
--boundary-query "select 1 as MIN , sum(1) as MAX from LZJHGX.T_JSZX_TF_KJ2_LL" \
--hcatalog-database dw \
--hcatalog-table ods_pre_T_JSZX_TF_KJ2_LL \
--hcatalog-storage-stanza 'stored as orc' \
--num-mappers 8

--query 参数的查询语句在Oracle中查询得到共计24563660数据,而加载到hive表dw.ods_pre_T_JSZX_TF_KJ2_LL中只有3070458数据。

24563660/8=3070457.5

这种巧合,刚好是一个mapper的向上取整量。这肯定有问题的,查看对应application的containers发现其实执行过程中是有做了split的:

例如mapper7,范围为:

复制代码
ROWNUM >= 15352287.875 AND ROWNUM < 18422745.250

这是mapper8,范围为:

复制代码
ROWNUM >= 18422745.250 AND ROWNUM < 21493202.625

但问题出现在Executing query,我把container7的语句放在Oracle中去执行,是没有返回任何结果集的:

但是container1中的Executing query查询却有结果集返回

这几个container中执行的Executing query查询,唯一不同的是条件ROWNUM的范围

复制代码
AND ( ROWNUM >= 1 ) AND ( ROWNUM < 3070458.375 )

那么ROWNUM到底是什么?为什么AND ( ROWNUM >= 1 ) AND ( ROWNUM < 3070458.375 )有结果集返回,而ROWNUM >= 18422745.250 AND ROWNUM < 21493202.625却没有?

要明白其中的原因,必须要明白Oracle中的ROWNUM到底是什么?

先看一组Oracle查询:

Oracle 的 ROWNUM 是一个特殊的伪列,它按查询返回的顺序动态分配给结果集中的每一行。因此,ROWNUM 仅在行被提取时分配,而不是基于数据表中的实际行号。

  1. 第一部分查询

    SELECT COUNT(*) FROM LZJHGX.T_JSZX_TF_KJ2_LL WHERE TO_CHAR(TJSJ , 'YYYY-MM-DD') < TO_CHAR(SYSDATE,'YYYY-MM-DD')

    • 这一部分返回符合 TJSJ 条件的所有记录数,结果为 24,563,660。这表明符合条件的记录总数就是这么多。
  2. 第二部分查询

    SELECT COUNT(*) FROM LZJHGX.T_JSZX_TF_KJ2_LL WHERE TO_CHAR(TJSJ , 'YYYY-MM-DD') < TO_CHAR(SYSDATE,'YYYY-MM-DD') AND ( ROWNUM >= 1 ) AND ( ROWNUM < 3070458.375 )

    • 这里你试图获取 ROWNUM13,070,458.375 范围内的行数。然而,ROWNUM 在分配时是严格递增的,它只能用于获取从头开始的连续行。也就是说,只要有 ROWNUM < 3,070,458.375 的限制,查询将返回符合条件的头 3,070,458 行。
    • 因此,这个查询实际上在返回总符合条件的前 3,070,458 行。
  3. 第三部分查询

    SELECT COUNT(*) FROM LZJHGX.T_JSZX_TF_KJ2_LL WHERE TO_CHAR(TJSJ , 'YYYY-MM-DD') < TO_CHAR(SYSDATE,'YYYY-MM-DD') AND ( ROWNUM >= 18422745.250 ) AND ( ROWNUM < 21493202.625 )

    • 这里的问题是,由于 ROWNUM 的工作方式,ROWNUM 永远不会满足 >= 18422745.250< 21493202.625 这样的区间查询。ROWNUM 是从 1 开始的递增序列 ,如果你直接使用 ROWNUM >= 某值 的条件,那么 Oracle 会从头重新生成行号,这种逻辑不支持从特定行号直接开始。因此,这个查询会返回 0 结果。

主要原因总结:

  • ROWNUM 是一个动态生成的递增伪列只能用于从查询的第一行依次生成,不能用来表示实际的物理行号。
  • 当你用条件 ROWNUM >= 某值 时,Oracle 会从第一个满足 WHERE 条件的行开始计算,无法跳过之前的行。

解决办法:所以在数据量很大时需要多个mapper并发执行时**ROWNUM万万不能作为splitby字段,**否则会出现数据量缺少,只有一个mapper数据量的问题。

方法1(不推荐):在--query利用开窗函数排序,数据量大时,非常消耗资源

方法2(推荐):将ROWNUM嵌套进子查询中,作为查询结果集中的一个字段,修改后的sqoop脚本如下:

bash 复制代码
sqoop import -D mapred.job.queue.name=highway \
-D mapreduce.map.memory.mb=4096 \
-D mapreduce.map.java.opts=-Xmx3072m \
-D sqoop.export.records.per.statement=1000 \
--fetch-size 10000 \
--connect "jdbc:oracle:thin:@//localhost:61521/LZY2" \
--username LZSHARE \
--password '123456' \
--query "SELECT * FROM(
SELECT
ROWNUM as splitby_column
,ZBDM
,ZBMC
,TO_CHAR(TJSJ, 'YYYY') AS tjsj_year
,TO_CHAR(TJSJ, 'MM') AS tjsj_month
,TO_CHAR(TJSJ, 'DD') AS tjsj_day
,TO_CHAR(TJSJ, 'YYYY-MM-DD HH24:MI:SS') AS TJSJ
,TJPD
......
,JLDWMC
,TO_CHAR(INPUTTIME, 'YYYY-MM-DD HH24:MI:SS') AS INPUTTIME
,UUID
,TO_CHAR(INSERTTIME, 'YYYY-MM-DD HH24:MI:SS') AS INSERTTIME
FROM LZJHGX.T_JSZX_TF_KJ2_LL
WHERE TO_CHAR(TJSJ , 'YYYY-MM-DD') < TO_CHAR(SYSDATE,'YYYY-MM-DD')) a WHERE \$CONDITIONS" \
--split-by splitby_column \
--hcatalog-database dw \
--hcatalog-table ods_pre_T_JSZX_TF_KJ2_LL \
--hcatalog-storage-stanza 'stored as orc' \
--num-mappers 20
相关推荐
大眼、不聚光9 分钟前
2.oracle--表空间管理
数据库·oracle
坚持学习前端日记14 小时前
Python SQLAlchemy ORM 从0到1精通实战手册(基础到复杂高阶)
数据库·python·oracle
小白说大模型18 小时前
LLM集成数据库的幻觉治理:当AI给出的SQL建议是错的
数据库·人工智能·sql·oracle·重构·开源
曹牧19 小时前
Oracle:空值排序
数据库·oracle
码农颜1 天前
6.1.2 常⽤⽅法的问题
数据库·sql·oracle
曹牧1 天前
Oracle:取固定分隔符字符串中第一个元素
数据库·oracle
NineData1 天前
NineData Oracle 到 ClickHouse 数据迁移完整流程:结构复制、全量装载、增量同步
数据库·clickhouse·oracle·数据迁移·ninedata·增量同步·数据迁移工具
zone_z1 天前
Oracle 数据库基础故障排查系列(12 篇)
数据库·oracle·dba·troubleshooting·blog-series
DBA_G1 天前
GBase 8a数据库RANGE分区操作详细解读
数据库·oracle
何以解忧,唯有..2 天前
数据库索引失效的常见情况与优化策略
数据库·sql·oracle