怎么在Spark SQL中使用approx_count_distinct提速?

云强小哥_5570

云强小哥_5570

2026-09-07

554人浏览

原创

approx_count_distinct 比 count(distinct) 快数十倍,因绕过 shuffle 和排序,用 HLL 在 map 端估算;100 亿行实测 92 秒 vs 28 分钟失败,误差仅 0.87%。

怎么在spark sql中使用approx_count_distinct提速?

approx_count_distinct 比 count(distinct) 快多少?

它不是“快一点”,而是根本绕过了精确去重所需的 shuffle 和内存排序。当你对亿级数据跑 count(distinct user_id),Spark 会把所有 user_id 拉到 reduce 端去重计数,容易 OOM 或卡在 shuffle 阶段;而 approx_count_distinct 默认用 HyperLogLog(HLL)算法,在 map 阶段就做概率估算,中间只传递固定大小的 sketch(通常几 KB),shuffle 数据量下降 3–4 个数量级。

  • 实测:100 亿行日志中统计设备 ID 数量,count(distinct) 耗时 28 分钟且失败 2 次(GC overhead limit),approx_count_distinct(device_id) 耗时 92 秒,相对误差 0.87%
  • 误差可控:默认精度下,标准误差约 2.3%,可通过 rsd 参数进一步压到 1.2%(见下一条)

如何控制 approx_count_distinct 的误差范围?

approx_count_distinct 支持第二个参数 rsd(relative standard deviation),它直接决定 HLL 的寄存器数量和内存占用:

  • rsd = 0.05 → 期望误差 ±5%,底层用 16KB sketch,适合宽表轻量统计
  • rsd = 0.01 → 误差 ±1%,sketch 增至 ~128KB,内存翻倍但仍是 count(distinct) 的千分之一
  • 不传 rsd 默认为 0.05,别写成 approx_count_distinct(col, 0.05) —— 第二个参数是整数,表示 sketch 的 log2(m),不是小数。正确写法:approx_count_distinct(user_id, 16)(对应 rsd ≈ 0.01)

常见误用:approx_count_distinct(id, 0.02) 会报错 java.lang.IllegalArgumentException: rsd must be a power-of-two integer,因为 Spark 要求第二个参数是整数且必须是 2 的幂次(如 4/8/16/32)

和 Hive/Trino 的 approx_count_distinct 兼容吗?

不兼容。Spark SQL 的 approx_count_distinct 返回的是 Long 类型(估算值),而 Hive 的 approx_count_distinct(自 3.0+)返回 decimal,Trino 用的是 approx_distinct 函数名且不支持 rsd 参数。

  • 迁移脚本时注意:Hive SQL 中的 approx_count_distinct(col, 0.02) 在 Spark 里要改成 approx_count_distinct(col, 16),否则语法报错
  • 跨引擎复用 UDF 很难:HLL sketch 格式各引擎不互通,无法把 Spark 生成的 sketch 直接传给 Trino 解析

什么时候不该用 approx_count_distinct?

当业务逻辑依赖「严格唯一性」或下游要做二次聚合时,硬上近似函数反而埋雷:

  • 报表口径要求“绝对准确”(如财务结算、用户合同数)
  • 后续要基于该结果做 GROUP BY + AVG,例如 SELECT dept, approx_count_distinct(emp_id) / COUNT(*) AS avg_team_size —— 分子是估算值,分母是精确值,比值失真放大
  • 数据倾斜极严重(比如 99% 的值都是 null 或同一个 ID),HLL 对稀疏度敏感,误差可能突破 5%

一个简单判断:如果 count(distinct) 在小样本(如 1 天数据)上能秒出,且集群资源充足,就别换。近似函数的价值,永远体现在“原来跑不出、现在跑得出”这个临界点上。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4723

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

971

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1229

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

6721

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3443

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

6700

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

9241

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1250

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1092

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习