Spark SQL多列Distinct含Null值时结果异常问题咨询
问题原因与解决方案
核心差异:多列count(distinct)与子查询去重计数的实现逻辑不同
在Spark 3.5.0(Databricks 14.1)中,count(distinct col1, col2, ...)和先select distinct再count(*)的处理逻辑存在关键区别,尤其是当存在null值时:
1. count(distinct ParameterId, Period, CalendarPeriod, RevisionDate)的实现
Spark会将多列打包成一个结构体(struct),然后对这个结构体进行哈希聚合去重计数。但在处理包含null的结构体时,Spark的哈希计算逻辑存在偏差:部分包含null但其他列不同的行,会被错误地判定为相同的结构体,导致去重计数结果与实际唯一行数不符。
2. 子查询select distinct再count(*)的实现
这种方式是先对全表的行进行行级别去重(逐行比较所有列的相等性:null与null视为相等,null与非null视为不等),生成包含所有唯一行的临时数据集,再对临时数据集计数,结果是精确的行级别唯一值数量。
验证与解决方案
调整配置统一行为
Spark提供了遗留配置项,让count(distinct多列)的行为与子查询去重计数一致:
SET spark.sql.legacy.countDistinctMultipleColumns = true;
重新执行df1的查询,结果会和df3一致(28685985)。
替代写法(无需修改配置)
直接使用df3的写法,这种方式在所有Spark版本中都能保证精确的行级别去重计数,不受null值影响:
SELECT COUNT(*) FROM ( SELECT DISTINCT ParameterId, Period, CalendarPeriod, RevisionDate FROM xxx.v3_2.consensus_normalized )
补充说明
df2的结果与df1不同,是因为去掉了含null的CalendarPeriod列,哈希聚合的偏差场景消失。- 该问题是Spark 3.0+版本引入的行为变化,默认配置下
count(distinct多列)的哈希聚合逻辑与行级别去重逻辑不一致,导致null场景下计数偏差。
内容的提问来源于stack exchange,提问作者lnshi
相关产品推荐
相关产品推荐

