You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark 3.1.3中Decimal类型round结果不符及优化关闭咨询

关于Spark 3.1.3 Decimal除法后Round精度不符的问题

问题重现代码

Dataset<Row> dataset = loadSource();  // 可忽略
dataset = dataset.withColumn("a", lit(1));  // 可忽略
dataset = dataset.withColumn("round", functions.round(lit(1).divide(lit(3)), 8)); // ①
dataset = dataset.withColumn("round2", functions.round(lit(1).cast(DataTypes.createDecimalType(35, 10)).divide(lit(3).cast(DataTypes.createDecimalType(35, 10))), 8)); // ②

dataset.explain(true);
dataset.show();

执行结果

roundround2
0.333333330.333333

预期round2结果同样为0.33333333,但实际仅保留6位小数。

执行计划对比

-- round的执行计划
round((cast(1 as double) / cast(3 as double)), 8) AS round

-- round2的执行计划
round(CheckOverflow((promote_precision(cast(cast(1 as decimal(35,10)) as decimal(35,10))) / promote_precision(cast(cast(3 as decimal(35,10)) as decimal(35,10)))), DecimalType(38,6), true), 8) AS round2

从执行计划可见,round2的Decimal除法结果被CheckOverflow限制为DecimalType(38,6),导致后续Round到8位小数时已无足够精度支撑。


解决方案:关闭Decimal溢出检查

可以通过设置Spark配置参数关闭Decimal运算的溢出检查,从而保留足够精度:

代码中配置

spark.conf().set("spark.sql.decimalOperations.allowPrecisionLoss", "false");
spark.conf().set("spark.sql.ansi.enabled", "false");

提交命令中配置

--conf spark.sql.decimalOperations.allowPrecisionLoss=false --conf spark.sql.ansi.enabled=false

参数说明

  • spark.sql.ansi.enabled:关闭ANSI模式后,Decimal运算不会强制触发溢出检查与截断;
  • spark.sql.decimalOperations.allowPrecisionLoss:设为false时,Decimal运算会尽量保留精度,避免自动截断到低精度类型。

修改配置后,round2的执行计划将移除CheckOverflow限制,除法结果保留足够小数位,最终Round到8位时即可得到预期的0.33333333。


内容的提问来源于stack exchange,提问作者Grand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:57:40