问题描述/异常栈
某客户在执行sql任务时,部分用户遇到如下错误:
User class threw exception: org.apache.spark.sql.AnalysisException
Cannot write incompatible data to table 'XXXXXXXXXX'
- Cannot safely cast 'age': string to int
- Cannot safely cast 'person_quantity': string to bigint
- Cannot safely cast 'ticket_quantity': string to bigint
FAQ-spark任务报错:Cannot write incompatible data to XX - 图1
发现版本
Spark 3.3.1
Kyubbi 1.8.0
问题原因
"spark.sql.storeAssignmentPolicy"参数默认值变更导致:
1、默认参数变更详情
环境 spark.sql.storeAssignmentPolicy参数默认值 说明
老环境 LEGACY 允许宽松的隐式类型转换
新环境 ANSI 严格类型检查,防止数据损坏
2、参数策略对比
维度 ANSI(新环境) LEGACY(老环境)
string → int 转换 不自动转换,直接报错 尝试隐式转换,失败多为NULL
非法值处理(如'abc') 直接抛异常 多数返回NULL,不抛异常
老SQL兼容性 较差,需要显式转换 较好,多数老SQL能继续运行
数据质量保障 高,问题早暴露 低,容易出现静默数据损坏
多环境一致性 高,前提是都配成ANSI 低,各环境配置不一难排查
适用场景 生产环境、数仓、财务/指标任务 老系统兼容、PoC、临时SQL
3、参数变更原因
LEGACY模式下存在数据静默损坏风险。例如,字符串"abc"转换为数字时变成NULL,导致指标计算错误且难以排查。ANSI模式强制显式转换,提高数据质量。
解决方案
方案一:显式类型转换(推荐)
-- 错误示例 
INSERT INTO dwd_bly_j_order_realname 
SELECT name, age, person_quantity, ticket_quantity 
FROM source_table;

-- 正确示例 
INSERT INTO dwd_bly_j_order_realname 
SELECT 
    name, 
    CAST(age AS INT) AS age, 
    CAST(person_quantity AS BIGINT) AS person_quantity, 
    CAST(ticket_quantity AS BIGINT) AS ticket_quantity 
FROM source_table;
方案二:修改默认参数值为LEGACY
kyubbi:
FAQ-spark任务报错:Cannot write incompatible data to XX - 图2
spark:
FAQ-spark任务报错:Cannot write incompatible data to XX - 图3

作者:曹俊