数仓任务的日常问题和报错解决

文章探讨了在SQL查询中遇到左连接(leftjoin)后数据缺失的问题,分析了可能是由于字段变更或过滤条件导致的,并提供了检查和解决方法。同时,文章提到了在Hive中处理大数据时遇到的内存错误、分区过多导致的任务失败以及Oozie任务数量限制,建议调整任务划分、内存配置和使用合适的数据处理引擎。此外,还讨论了unionall操作过多对Spark程序的影响及解决方案。
摘要由CSDN通过智能技术生成

1.left join后少数据怎么办?

问题:sqL里互联网门诊科室字段有很多空白数据

分析:首先先看这个数据来源于哪个表,然后根据其left join的相关表一层层往上推,找最上面两个表join的原因,如果找不到再往下找

原因:为什么要这么做,因为某表缺数据,说明前面的表left Join的时候可能没join上,导致后面一层层都缺数据

操作:我们通过查询发现确实是最前面俩表join的时候,右表经常Join不上,然后我们查一下能join上的左表的最大ctime

select
max(e.ctime)
from dwb.healthpal_avatar_healthservicerecords e
LEFT JOIN dwb.onlinehospital_avatar_totalorderitems ti ON ti.orderid=e.providerid AND ti.ordertype=e.providerType
where ti.ordertype is not null

查询到最大的ctime是2022-04-27 01:03:20

然后我们卡住这个ctime,验证一下是不是从这天以后右表就一直join不上了,join不上的时候左表的链接字段分别是什么

select
e.ctime,
e.providerid,
e.providerType,
ti.ordertype,
ti.orderid
from dwb.healthpal_avatar_healthservicerecords e
LEFT JOIN dwb.onlinehospital_avatar_totalorderitems ti ON ti.orderid=e.providerid AND ti.ordertype=e.providerType
where e.ctime > '2022-04-27'

发现此时左表的Porvideid全是0,这是导致右表Join不上的根本原因

那为什么会这样?是这个字段废弃不用了吗?那现在用的是哪个字段呢?

select providertype,count(1),min(ctime),max(ctime) from dwb.healthpal_avatar_healthservicerecords group by providertype;
select sourcetype,count(1),min(ctime),max(ctime) from dwb.healthpal_avatar_healthservicerecords group by sourcetype;

查询到确实从4月27开始我们拿到得类型都为空,说明换字段了,我们猜测一下是否换了sourcetype字段

同样方法查询可知确实sourcetype的BasicOrder的数量最多,且延续至今,因此用的应该是该字段

2.left join少数据一定是表字段废弃吗?

说明:left join少数据并不一定是表字段废弃关联未成功导致,也可能是我们过滤的问题,不妨将过滤条件放开试试

问题:团队工作量中,多行只有baseteamid却缺少用户名等字段

方法:还是老方法,看缺少的这个字段来源于哪个表,他是和谁join,然后找出相应的表排查原因

原因:1. 有些医生注销了,但有其工作量数据,我们不应该过滤掉is_open不为identical的数据

2.机构的工作量不应该存在于内,而机构在tab_space表,在spase_user和spase_user_predoctor表均未收录,所以left join时无法将其取出

解决方式:1.取消过滤条件where is_open = 'identical'

2.我们可以直接过滤掉space_userid为空解决,或额外取出院队名称做为标注也可解决以后的麻烦 where space_user_id is not null group by baseteamid,dth.name

3.关于from_unixtime和get_json_object函数

from_unixtime(get_json_object(get_json_object(content,'$.data'),'$.fld_SpaceHitsCreateTime'),'yyyy-MM-dd')dt解析出来的为字符串,但在Hive里严格要求该参数为int,但为什么这里不强转也可以?

  * @param ut A number of a type that is castable to a long, such as string or integer. Can be
   *           negative for timestamps before the unix epoch
   * @return A string, or null if the input was a string that could not be cast to a long
   * @group datetime_funcs
   * @since 1.5.0
   */
  def from_unixtime(ut: Column): Column = withExpr {
    FromUnixTime(ut.expr, Literal("yyyy-MM-dd HH:mm:ss"))
  }

源码里给了我们想要的答案,其实第一个字段为column类型,他会在底层先转为string,然后再转为long类型统一处理,

所以即使你这里强转为了Int,他还是会重新转为string,所以外部没必要加强转,而后面的格式字段是严格要求为string类型的,当然也可以不传值,底层会给一个默认值

什么是column类型:Column 表示了 Dataset 中的一个列, 并且可以持有一个表达式, 这个表达式作用于每一条数据, 对每条数据都生成一个值

那为什么我的分区字段传错了,表里没有这个字段,只有分区分到了hive默认分区,但是程序却不报错?

因为是get_json_object方法,如果没有那个字段,就返回null,然后在调用null的该方法当然还是null,所以除了content不能写错以外,其他的data和后面的time写错了都不会报错,结果为null,

到了底层的FromUnixTime,接收一个Null,直接返回Null,结果分区字段就是null值,自然分到默认分区了

4.合并任务失败

首次执行:

Caused by: java.net.SocketTimeoutException: Readtimed out

原因:由于这是一个新的分区表,一边写分区文件一边创建新的分区,就会导致一个问题,对于spark引擎,创建新分区数量过多,就会读写超时,大约上限是1000个分区

这里要分几种情况,视情况而定如何解决:

  1. 分区多但文件小:使用MR引擎解决,MR不在乎创建多少个分区,也不在乎map数量多与少,但他怕一件事,对reduce端有内存限制40G,由于我们想要的是一个分区下就一个文件,因此只启动一个reduce的情况下, 文件小适用,而如果数据量大则会reduce内存不够;当数据量大时,其实也可以采用该种方式解决,启动多个reduce,但需要最后对reduce端输出的小文件进行合并,也就是单独启动一个reduce任务进行合并处理,但这种方式,仍存在一定局限性,假如数据量就是太大,最后一个reduce内存不够合并也失败呢?而且由于是MR引擎,不会像spark一样直接reduce后立马接一个reduce进行合并,它会再发给map,然后再给reduce,而数据量又大,大量的磁盘IO,这显然是并不太合适的

  1. 分区多且文件大:使用分多个任务卡ctime的方式解决,既然一个任务不够处理1000以上的分区,那我分两个或多个任务,每两年一个任务行不行?或使用脚本读取最大和最小的ctime提前将分区自动化创建好,然后一个spark任务进行合并即可;

  1. 分区少但文件大:这种情况没得说,直接上单个spark任务即可

  1. 分区少且文件小:同上

夜间执行:

Application attempt appattempt_1660014269451_69923_000002 doesn't exist in

ApplicationMasterService cache

unning 34807808B beyond the 'PHYSICAL' memory limit. Current usage: 3.5 GB of

3.5 GB physical memory used; 5.5 GB of 7.3 GB virtual memory used. Killing

container.

原因:最常见的报错,资源紧张,内存不足,appmaster直接被kill,适量增大excutor内存

5.内存错误

合ods历史数据时如果涉及分区过多,可以用hive任务执行,此时需要自己配置参数

msck repair table ods_binlog.ods_binlog_intention_avatar_notifications_di,
set mapreduce.map.memory.mb=2048,
set mapreduce.reduce.memory.mb=20480,
set hive.exec.reducers.max=1,
set mapred.reduce.tasks=1

其中mapred.reduce.tasks和hive.exec.reducers.max设置一个即可,前者代表所有任务中的reduce个数,后者代表每个任务也就是stage的最大个数,当底层公式计算的个数比该值大时,生效该值,小时生效计算值,但这里无论生效哪个,当reducetask个数设置时,直接以reducetask为准,公式为nvl(reducetask, min(reducemax, min(1009, 程序计算)))

因为只给一个reduce所以内存可相应给大点,否则会报gc和oom,map也可以相应增大

但是如果给的太大,例如40g,会直接报错

翻译为所需的REDUCE能力大于集群中支持的最大容器能力。杀死的工作

6.create ods table报错和改表名的一些注意事项

问题:创建instantmessage_avatar_immessages的ods表时一直报错key找不到

原因:我明明在数仓基础表里加入了这一行记录,但找不到,后来查询原因是该表不是mysql表,为mongo表,也就是说我在读取元数据创建ods的时候会找不到相应的元数据,自然找不到key

延伸:该表已经存在dwb目录下,但不是Kudu表,其实Mongo同步过来的hive表,相当于ods层,dwd层也有其相应任务,但其表名不太规范

解决办法:我先将其原名查询哪些任务依赖于该表,然后再改表名并修改数仓存储引擎和依赖于该表的sql

问题:但改表名时发生了一件奇怪的事情,改表名时映射Location和hdfs中的文件名都一起修改了,可我之前这些都需要手动改正

思考:我就怀疑是内外表改表名时,修改逻辑不一样,通过测试并观察文件名和建表语句的location确实验证了我的猜想

CREATE TABLE tmp.test002 (   id INT ) STORED AS TEXTFILE LOCATION 'hdfs://HDFSNS/Data/d1/hive/warehouse/tmp.db/test002';
ALTER TABLE tmp.test002 RENAME TO tmp.test0002;
show create table tmp.test0002;
ALTER TABLE tmp.test0002 SET TBLPROPERTIES('EXTERNAL' = 'TRUE');
ALTER TABLE tmp.test0002 RENAME TO tmp.test002;
show create table tmp.test002;
CREATE TABLE tmp.test003 (   id INT ) STORED AS TEXTFILE;

得出结论:内表改表名Location和文件名自动发生相应变化,由此也可以知道内表不用给location,外表改表名只是单纯改了表名而已

拓展:hue没办法把表名改成大写,因为在hue中不管你敲大小写,底层都识别为小写,只能通过脚本的方式去改不然一直报错视图找不到

7.关于oozie任务数量多报错

oozie任务有数量限制,任务数量超过限制会挂掉,需要在oozie-site.xml中增加参数

参考链接:https://github.com/Shopify/pyoozie/issues/33

8.关于union all数量过多

当union all数量过多时,程序会直接在分配容器时立马报错结束,而不是在运行到某个exctor的stage结束,也就是说两次失败执行的时间都很短,这就说明是driver端出现了问题

问题原因:在Spark程序中,SparkContext,DAGScheduler都是运行在Driver端的。对应rdd的Stage切分也是在Driver端运行,如果用户自己写的程序有过多的步骤,切分出过多的Stage,这部分信息消耗的是Driver的内存,这个时候就需要调大Driver的内存

解决方式:将driver端内存从3g增加到5g,excutor不用动,之后就可以正常运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值