Dataworks实践—报错原因及处理

2024-08-12 10:54:44 浏览数 (1)

1.0 引言

目前maxcompute中已经有对应的错误码附录,具体链接请查看官网链接,这里就不一一详细注明了 ,这里也将其主要内容复制如下,具体内容还请通过官网查阅。

但官网的情况并没有涵盖所有的,或者说我只介绍我数据开发过程中遇到的”坑“或者更通常见到的错误,希望大家在以后的数据开发中避免。

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

2.1 数字溢出报错说明
数字溢出数字溢出

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

类型

常量示例

描述

TINYINT

1Y,-127Y

8位有符号整型,取值范围-128~127

SMALLINT

32767S,-100S

16位有符号整型,取值范围-32768~32767

INT

1000,-15645787

32位有符号整型,取值范围 -2^31 ~ 2^31-1

BIGINT

100000000000L,-1L

64位有符号整型,取值范围 -2^63 1 ~ 2^63-1

BINARY

二进制数据类型,目前长度限制为8MB

FLOAT

32位二进制浮点型

DOUBLE

3.1415926 1E 7

64位二进制浮点型

DECIMAL(precision,scale)

3.5BD,99999999999.9999999BD

10进制精确数字类型 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。

DATE

DATE'2023-06-09'

日期类型,格式为yyyy-mm-dd。 取值范围:0000-01-01~9999-12-31。

DATETIME

DATETIME'2023-06-09 00:00:00'

日期时间类型。 取值范围:0000-01-01 00:00:00.000~9999-12-31 23:59:59.999,精确到毫秒。

TIMESTAMP

TIMESTAMP'2023-06-09 00:00:00:123456789'

时间戳类型。 取值范围:0000-01-01 00:00:00.000000000~9999-12-31 23:59:59.999999999,精确到纳秒。

BOOLEAN

True,False

BOOLEAN类型 取值范围:True、False。

2.2 实际业务场景

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

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

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

代码语言:sql复制
select 
	from_unixtime(int(create_time/1000)) as create_time
from target_table

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

代码语言:sql复制
select 
	from_unixtime(cast(create_time/1000 as bigint)) as create_time
from target_table
2.3 报错的启示

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

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

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

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

3.2 实际业务场景
代码语言:sql复制
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结果select结果

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

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

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

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

代码语言:sql复制
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结果1
代码语言:sql复制
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结果2
4.2 隐式转换错误说明

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

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

void

boolean

tinyint

smallint

int

bigint

float

double

decimal

string

varchar

timestamp

date

binary

void to

true

true

true

true

true

true

true

true

true

true

true

true

true

true

varchar to

false

false

false

false

false

false

false

true

true

true

true

false

false

false

tinyint to

false

false

true

true

true

true

true

true

true

true

true

false

false

false

timestamp to

false

false

false

false

false

false

false

false

false

true

true

true

false

false

string to

false

false

false

false

false

false

false

true

true

true

true

false

false

false

smallint to

false

false

false

true

true

true

true

true

true

true

true

false

false

false

int to

false

false

false

false

true

true

true

true

true

true

true

false

false

false

float to

false

false

false

false

false

false

true

true

true

true

true

false

false

false

double to

false

false

false

false

false

false

false

true

true

true

true

false

false

false

decimal to

false

false

false

false

false

false

false

false

true

true

true

false

false

false

date to

false

false

false

false

false

false

false

false

false

true

true

false

true

false

boolean to

false

true

false

false

false

false

false

false

false

false

false

false

false

false

binary to

false

false

false

false

false

false

false

false

false

false

false

false

false

true

bigint to

false

false

false

false

false

true

true

true

true

true

true

false

false

false

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

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 - 通用参考错误码附录

0 人点赞