如何解决Druid SQL同一查询中结合其他列使用多个COUNT(DISTINCT)时的查询计划构建失败问题?
解决Druid多COUNT(DISTINCT)查询报错的问题
我来帮你搞定这个Druid查询的问题!你遇到的报错是因为Druid对同时处理多个复杂的COUNT(DISTINCT)统计项有一定限制,尤其是当其中还包含CASE WHEN、字符串拼接这类复杂表达式的时候,查询计划构建会失败。下面给你几个可行的解决方案:
1. 拆分查询为子查询关联
把两个COUNT(DISTINCT)拆分成两个独立的子查询,再通过__time关联结果,这是最稳妥的精确统计方案:
SELECT t1.__time, t1.distinct_col1_count, t2.distinct_concat_count FROM ( SELECT __time, COUNT(DISTINCT col1) AS distinct_col1_count FROM table WHERE condition3 GROUP BY __time ) t1 JOIN ( SELECT __time, COUNT(DISTINCT CASE WHEN condition1 AND condition2 THEN CONCAT(col2, TIME_FORMAT(__time)) ELSE NULL END) AS distinct_concat_count FROM table WHERE condition3 GROUP BY __time ) t2 ON t1.__time = t2.__time
⚠️ 注意:我把你原SQL里的ELSE 0改成了ELSE NULL,因为原来的写法会把所有不符合条件的行都计入0这个值,导致distinct count包含额外的0,这大概率不是你想要的结果。
2. 使用近似聚合函数(适合非精确场景)
如果你的业务场景允许近似统计结果,可以用Druid原生支持的APPROX_COUNT_DISTINCT代替COUNT(DISTINCT)。这个函数对多实例的支持更好,性能也远高于精确的COUNT(DISTINCT):
SELECT __time, APPROX_COUNT_DISTINCT(col1), APPROX_COUNT_DISTINCT(CASE WHEN condition1 AND condition2 THEN CONCAT(col2, TIME_FORMAT(__time)) ELSE NULL END) FROM table WHERE condition3 GROUP BY __time
3. 升级Druid版本或调整配置
- 如果你的Druid版本比较旧(比如低于0.20.x),升级到新版本会改善对多
COUNT(DISTINCT)的支持,新版本在查询计划优化上做了很多改进。 - 你也可以尝试调整Druid的查询配置参数,比如增加
druid.query.groupBy.maxOnDiskStorage、druid.query.groupBy.maxMergingDictionarySize的取值,给查询分配更多内存资源,但这个方法只能缓解小数据量的情况,不如前两种方案可靠。
4. 预计算维度(适合高频查询)
如果这个查询是经常执行的,可以在数据摄入阶段提前处理:
- 把
CONCAT(col2, TIME_FORMAT(__time))的结果作为一个新的维度列提前生成,这样查询时就不需要实时拼接字符串。 - 利用Druid的Rollup功能,在数据摄入时预计算部分聚合结果,减少查询时的计算压力。
内容的提问来源于stack exchange,提问作者N S




