Spark中Decimal类型相乘无溢出却返回NULL的问题咨询
Spark Decimal相乘返回NULL的原因解析
问题场景
将类型为DecimalType(38,10)和DecimalType(38,16)的两列数值相乘,结果列类型被推导为DecimalType(38,22),且已通过配置禁用精度损失(spark.sql.decimalOperations.allowPrecisionLoss=false)。按照官方文档描述,仅当数值过大导致整数部分溢出时结果才会返回NULL,但实际中即使是30858938444.540 × 1这类简单操作,结果也返回NULL。
核心原因
Spark对Decimal类型的乘法运算遵循以下逻辑:
- 中间结果计算:两个Decimal相乘时,中间结果的精度为
p1 + p2(即38+38=76),小数位数为s1 + s2(即10+16=26)。 - 目标类型适配检查:当禁用精度损失时,Spark要求中间结果必须无损适配到目标结果类型
DecimalType(38,22),既不能截断小数位,也不能让整数部分溢出。 - 触发NULL的场景:示例中的
30858938444.540 × 1得到的中间结果小数位是26位,但目标类型仅支持22位小数。由于禁用了精度损失,Spark不允许截断多余的4位小数,因此直接返回NULL——这并非整数部分溢出,而是小数位精度无法无损保留导致的。
验证解决方法
- 降低参与计算的Decimal列小数位数:比如将其中一列的小数位调整为12,相乘后中间结果小数位为22,刚好匹配目标类型,可正常返回结果。
- 开启允许精度损失配置:设置
spark.sql.decimalOperations.allowPrecisionLoss=true,Spark会自动截断多余的小数位,返回符合目标类型的结果。
内容的提问来源于stack exchange,提问作者Grevioos
相关产品推荐
相关产品推荐

