聊聊阿里云Dataworks实践,一些报错及其解决办法

918 阅读8分钟

1.0 引言

目前maxcompute中已经有对应的错误码附录,具体链接请点击跳转 ,这里也将其主要内容复制如下,具体内容还请通过链接进行查阅。

但这里的情况并没有涵盖所有的,或者说我只介绍我数据开发过程中遇到的”坑“或者更常见到的错误,希望大家在以后的数据开发中避免。常言道:千里之堤,溃于蚁穴,这些小问题有时候会成为压倒骆驼的最后“一棵稻草”。

2.0 数字溢出错误描述以及应对措施

2.1 数字溢出报错说明

数字溢出

这个错误是非常常见的一个问题,即double转换到int,数字溢出。那么这里来说下Maxcompute 2.0数据类型。

Maxcompute 2.0数据类型

类型常量示例描述
TINYINT1Y,-127Y8位有符号整型,取值范围-128~127
SMALLINT32767S,-100S16位有符号整型,取值范围-32768~32767
INT1000,-1564578732位有符号整型,取值范围 -2^31 ~ 2^31-1
BIGINT100000000000L,-1L64位有符号整型,取值范围 -2^63+1 ~ 2^63-1
BINARY二进制数据类型,目前长度限制为8MB
FLOAT32位二进制浮点型
DOUBLE3.1415926 1E+764位二进制浮点型
DECIMAL(precision,scale)3.5BD,99999999999.9999999BD10进制精确数字类型 precision:表示最多可以表示多少位的数字。取值范围:1<=precision<=38 scale:表示小数部分的位数。取值范围:0<=scale<=18 如果不指定以上两个参数,则默认为decimal(38,18)
VARCHAR(n)变长字符类型,n为长度;取值范围:1~65535
CHAR(n)固定长度字符类型,n为长度。最大取值255.长度不足则会填充空格,但空格不参与比较
STRING"abc","bcd","alibaba"字符串类型,目前长度限制为8 MB。
DATEDATE'2023-06-09'日期类型,格式为yyyy-mm-dd。 取值范围:0000-01-01~9999-12-31。
DATETIMEDATETIME'2023-06-09 00:00:00'日期时间类型。 取值范围:0000-01-01 00:00:00.000~9999-12-31 23:59:59.999,精确到毫秒。
TIMESTAMPTIMESTAMP'2023-06-09 00:00:00:123456789'时间戳类型。 取值范围:0000-01-01 00:00:00.000000000~9999-12-31 23:59:59.999999999,精确到纳秒。
BOOLEANTrue,FalseBOOLEAN类型 取值范围:True、False。

2.2 实际业务场景

其中可以看到,int类型的最大值约为2147483647,smallint类型的最大值为32767,tinyint类型的最大值为127。而上述截图中的报错即是由于超出了int的范围导致,不过通过此报错我想说的问题不在于此。具体的场景如下:

公司生产数据中,时间戳字段都是整型,如下:

image-20230612112138742

时间戳是带有时分秒的,在实际宽表的建设中,我们需要对该时间戳进行解析,而最简单的处理方式是如下的,并且也不报错,以致于目前几乎所有的时间戳的解析均是利用该逻辑来处理。

 select 
     from_unixtime(int(create_time/1000)) as create_time
 from target_table

但是,如果数据库中的时间戳来到了2147483647,也就是日期超过2038-01-19 11:14:07一秒以后,整体的含上述解析逻辑的脚本全部会报错,就会导致整体的调度失败,影响生产数据的产出,带来重大的生产事故。因此,比较好的调整方式如下:

 select 
     from_unixtime(cast(create_time/1000 as bigint)) as create_time
 from target_table

2.3 报错的启示

对于业务中的脚本逻辑,要进一步思考其本身的合理性和脚本的适配性,保证脚本的健壮性。

3.0 插入列少于目标列数错误描述以及应对措施

3.1 插入列少于目标列数报错说明

报错列数少于目标列

这个错误其实可以通过报错上很容易看出来,意思是在目标表中有5列,插入的数据中只有四列。而遇到这样的报错的情况下,我们很容易的想到是我们在手工输入的时候少输入了一列导致的,但是我们来看下脚本:

3.2 实际业务场景

 create table yht_dw_dev.t_charge_detail(
     charge_id string COMMENT '',
     keep_id string COMMENT '',
     bill_id string COMMENT '',
     ar_ap string COMMENT '',
     amount string COMMENT ''
 );
 ​
 insert overwrite table yht_dw_dev.t_charge_detail
 select 
 charge_id
 ,keep_id
 bill_id
 ,ar_ap
 ,amount
 from yht_dwd.dwd_sea_charge_detail 
 where pt='${bizdate}'
 limit 100

目标表中为五列分别是charge_id,keep_id,bill_id,ar_ap,amount,而脚本中的插入语句仔细数一数也同样是五列呀,我们再单独执行一下select 语句,发现语法正确,不过只展示了四列结果出来:

select结果

但是我们仔细观察语句和结果的区别可以看到:keep_id和bill_id字段中间缺少了逗号字段,导致两个字短变成了一个字短,但是语法却仍然可以跑通,这也是需要我们注意的地方:报错缺少列除了我们真的少写了真实的列,实际上也可以是我们少写了一个逗号导致多列变成单列,这是我们需要在实际中需要注意的。

4.0 隐式转换错误描述以及应对措施

4.1隐式转换错误实际业务场景

这个错误其实不太容易发现,但是却很致命,比如下面两段脚本:

 select 
 id, 
 charge_confirmation_id, 
 charge_confirmation_id=1640966400016064464 
 from yht_dw.ods_cw_fin_charge_df 
 where pt='${bizdate}'
 and charge_confirmation_id=1640966400016064464

结果如下:

结果1

 select 
 id, 
 charge_confirmation_id,
 charge_confirmation_id='1640966400016064464'
 from yht_dw.ods_cw_fin_charge_df
 where pt='${bizdate}'
 and charge_confirmation_id='1640966400016064464'

结果2

4.2 隐式转换错误说明

上述两个脚本其实只存在一处差异,即在where条件中的数字加了单引号转化为字符串和没有加单引号为bigint类型,而最后的结果是第一段脚本执行的结果为6条记录,而第二段脚本的执行结果为7265条记录,而通过两段脚本的比较,我们也会发现第一段的结果是正确的,而第二段脚本的执行结果是错误的,具体对照第二列和条件即可辨别。而具体导致的因素就是hive本身的数据类型的隐式转换。

也就是说,第一段脚本,需要将charge_confirmation_id转化为条件中等号右侧的bigint类型,而charge_confirmation_id本身即为bigint类型,所以,不需要转换,直接过滤得到结果;第二段脚本,charge_confirmation_id为bigint类型,而等号右侧为字符串类型,这样在隐士转换中出现问题,导致转换丢失了精度,导致结果异常,以下是hive官方文档中的隐士转换结果表。

Allowed Implicit Conversions

voidbooleantinyintsmallintintbigintfloatdoubledecimalstringvarchartimestampdatebinary
void totruetruetruetruetruetruetruetruetruetruetruetruetruetrue
varchar tofalsefalsefalsefalsefalsefalsefalsetruetruetruetruefalsefalsefalse
tinyint tofalsefalsetruetruetruetruetruetruetruetruetruefalsefalsefalse
timestamp tofalsefalsefalsefalsefalsefalsefalsefalsefalsetruetruetruefalsefalse
string tofalsefalsefalsefalsefalsefalsefalsetruetruetruetruefalsefalsefalse
smallint tofalsefalsefalsetruetruetruetruetruetruetruetruefalsefalsefalse
int tofalsefalsefalsefalsetruetruetruetruetruetruetruefalsefalsefalse
float tofalsefalsefalsefalsefalsefalsetruetruetruetruetruefalsefalsefalse
double tofalsefalsefalsefalsefalsefalsefalsetruetruetruetruefalsefalsefalse
decimal tofalsefalsefalsefalsefalsefalsefalsefalsetruetruetruefalsefalsefalse
date tofalsefalsefalsefalsefalsefalsefalsefalsefalsetruetruefalsetruefalse
boolean tofalsetruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalse
binary tofalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetrue
bigint tofalsefalsefalsefalsefalsetruetruetruetruetruetruefalsefalsefalse

隐式转换的总结主要有以下几点:

hive转换时包括隐式转换(implicit conversion)和显式转换(explicitly conversion)

比如我们对两个不同数据类型的数字进行比较,加入一个数据类型为int型,一个是smallint类型,那么smallint类型的数据就会被隐式转换为int类型;但是我们不能隐式地将一个int类型的数据转换为smallint或tinyint类型的数据,这将会返回错误,除非你用了cast操作

任何整数类型都可以隐式地转换为一个范围更大的类型。tinyint,smallint,int,bigint,float和sring都可以隐式的转换为double

boolean类型不能转换为其他任何数据类型!如果强制转换的换会返回null

4.3 报错的启示

跟我之前强调的一样,hiveSQL是一种对数据类型进行强相关的结构性语言,因此在建表、join关联以及where条件筛选过程中都需要对数据类型进行特别关注,避免隐式转换,这样就避免产生一些底层的难以预知的错误,除非你可以记得住隐式转换表的内容。

5.0 参考文献

1 hive数据类型及数据类型转换的注意事项

2 隐式转换:Hive可以写3>2>1没用过吧?

3 Apache Hive language manual

4 云原生大数据计算服务 MaxCompute - 通用参考错误码附录