news 2026/7/15 21:24:49

Spark 3.x 动态分区裁剪:为什么它能自动跳过 90% 的数据扫描

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spark 3.x 动态分区裁剪:为什么它能自动跳过 90% 的数据扫描

Spark 3.x 动态分区裁剪:为什么它能自动跳过 90% 的数据扫描

一、从一个真实场景说起

大家好,我是朱大喜。先问大家一个问题:你们在 Spark 里做两张大表 JOIN 的时候,有没有遇到过一个尴尬的场景——明明事实表按日期分了 365 个分区,你只查最近 7 天的数据,但 Spark 硬是把 365 个分区的文件列表全都扫了一遍?

这不是 bug,而是 Spark 2.x 时代的设计局限。在 Spark 3.0 之前,静态分区裁剪只能在查询编译阶段,根据 WHERE 条件中直接写在 SQL 里的过滤条件来跳过分区。一旦过滤条件隐藏在另一张小表里(比如 JOIN 之后的 ON 条件),优化器就没办法在扫描阶段做裁剪了。

打个生活化的比方:你家里有 365 个抽屉,每个抽屉标着日期。你要找"最近 7 天老婆买过的所有东西"。老婆买过什么记录在一个小本子上(维度表),具体买了啥记在一堆购物小票里(事实表)。聪明人会先翻小本子找出最近 7 天她确实买了东西的那几天,然后只开那几个抽屉。但 Spark 2.x 就像个耿直的机器人,它会老老实实把 365 个抽屉全打开看一眼,然后再跟小本子对日期——白白开了 350 多个没用的抽屉。

二、动态分区裁剪的魔法在哪里

Spark 3.0 引入的动态分区裁剪(Dynamic Partition Pruning,简称 DPP),核心思路非常朴素:在运行时,把维度表的过滤结果作为广播变量,下推到事实表的扫描阶段,让事实表在读取文件时就跳过不相干的分区。

graph LR A[维度表<br/>dim_date] -->|过滤: 最近7天| B[过滤结果: 7个日期] B -->|Broadcast 广播| C{事实表扫描阶段} D[事实表<br/>fact_orders<br/>365个分区] --> C C -->|只扫描7个分区| E[JOIN 结果] style B fill:#4CAF50,color:#fff style C fill:#FF9800,color:#fff

这里的关键词是**"运行时""下推"**。静态裁剪发生在编译期,只能处理常量过滤条件;而动态裁剪发生在执行期,维度的过滤结果已经算出来了,可以直接拿来用。而且它是下推到文件扫描层面的,不是在 JOIN 之后才过滤,这就从根源上减少了数据读取量。

实际效果有多明显呢?我们团队有个订单分析场景:事实表 365 天分区 × 每天 2 亿行,维度表是一个几十 MB 的日期配置表。老版本 Spark 每次查询都要扫描全表再过滤,耗时 40 多分钟。升级到 Spark 3.x 并确认 DPP 生效后,同样的查询扫描数据量降到原来的 8%,耗时缩短到 3 分钟以内。

三、DPP 的触发条件,不是你想用就能用

DPP 虽然美好,但不是所有 JOIN 都能享受这个福利。它有严格的触发条件,理解这些条件才能写出"能被优化"的 SQL。

条件一:必须是等值 JOIN。ON 条件必须是=而不能是><LIKE。因为只有等值才能建立分区键之间的精确映射关系。

条件二:维度表必须足够小,能被广播。DPP 的前提是把维度表的过滤结果广播到所有 Executor。Spark 默认spark.sql.autoBroadcastJoinThreshold是 10MB,如果你的维度表超过这个大小,Spark 会退化为普通的 SortMergeJoin,不再触发 DPP。

条件三:事实表的分区键必须参与 JOIN 的 ON 条件。如果你的事实表按dt分区,但 JOIN 的 ON 条件是a.user_id = b.user_id,那 DPP 跟分区没关系,不会生效。只有 JOIN 键包含了分区键时,动态裁剪才有意义。

-- ✅ 会触发 DPP:dim_date.date_id 过滤后广播,下推到 fact_orders -- 的扫描阶段,只读取 dt 在最近7天内的分区 SELECT /*+ BROADCAST(d) */ f.* FROM fact_orders f JOIN dim_date d ON f.dt = d.date_id WHERE d.date_type = 'workday' AND d.date_id >= '2026-07-08'; -- ❌ 不会触发 DPP:JOIN 键是 order_id,跟分区键 dt 没关系 SELECT /*+ BROADCAST(d) */ f.* FROM fact_orders f JOIN dim_product p ON f.order_id = p.order_id -- 不是分区键 WHERE f.dt >= '2026-07-08'; -- 这里只能走静态裁剪

还有一个容易踩坑的地方:DPP 和 Bucket Join 是互斥的。如果你的表做了分桶(Bucket),而 Spark 选择了 Bucket Join 策略,DPP 就不会生效。这时需要在性能上做取舍——是分桶带来的 Shuffle 减少更香,还是 DPP 的数据量削减更猛。

四、如何验证 DPP 真的生效了

写完了 SQL,跑得也挺快,但你心里犯嘀咕:它到底走了 DPP 没有?Spark UI 里的信息说实话不太好读,我来教你怎么快速确认。

最直接的方法是在 Spark SQL 里用EXPLAIN看执行计划。如果你在扫描阶段看到dynamicpruning字样,恭喜你,DPP 起作用了。

# 在 PySpark 中验证 DPP 是否生效 spark.sql(""" EXPLAIN EXTENDED SELECT f.* FROM fact_orders f JOIN dim_date d ON f.dt = d.date_id WHERE d.date_type = 'workday' """).show(truncate=False) # 关键输出标志(看到这些就说明DPP生效了): # +- *(1) Project [order_id#123L, dt#124, ...] # +- *(1) BroadcastHashJoin [dt#124], [date_id#200], # :- *(1) Filter dynamicpruningexpression(dt#124 IN dynamicpruning#300) # | +- *(1) FileScan parquet fact_orders[dt#124,...] # | : +- DynamicPruningExpression # +- BroadcastExchange HashedRelationBroadcastMode(...) # +- *(2) Filter (date_type#202 = workday)

另外可以通过 Spark UI 的 SQL 页签来看。如果 DPP 生效了,你会看到 Scan 阶段的number of files read远小于总文件数。没有 DPP 时,365 个分区的文件可能全被列出来;有了 DPP,可能只读到了 7 个分区的文件。

经验之谈:如果 DPP 没生效,排查顺序是 1) 看维度表大小是否超过广播阈值 2) 看 JOIN 键是否就是分区键 3) 看有没有显式或隐式地禁用了 AQE(Adaptive Query Execution),因为 DPP 是 AQE 框架下的一个子功能。

五、总结

动态分区裁剪是 Spark 3.x 里投入产出比最高的优化之一。你不需要改代码,不需要调参数,只要你的 SQL 满足条件(等值 JOIN + 小维度表 + JOIN 键是分区键),Spark 就会自动帮你省掉大量无用数据扫描。

但别因为它自动就完全不管。写 SQL 时心里要有这条线:我的事实表分区键是哪个?维度表能不能再缩小一点让它进广播阈值?JOIN 条件能不能精确地包含分区键?这三个问题想清楚了,DPP 一般不会让你失望。

回到抽屉的比喻:Spark 2.x 是把所有抽屉打开再核对小本子,Spark 3.x 是先翻小本子确定是哪几个抽屉,然后只开那几个。这一前一后的差异,就是 40 分钟和 3 分钟的距离。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/15 21:24:30

2026年最新北京市轨道交通图和 北京轨道交通规划图 附图

北京市地铁运营有限公司&#xff08;简称“地铁公司”&#xff09;成立于1970年4月15日&#xff0c;是北京市市属大型国有独资公司&#xff0c;是国内最早成立的城市轨道交通运营企业&#xff0c;开通运营了新中国第一条地铁。地铁公司定位于“保障城市运行安全&#xff0c;提升…

作者头像 李华
网站建设 2026/7/15 21:23:52

LVGL学习(四)- Objects

一、简介前面介绍的东西都比较简单&#xff0c;这篇文章介绍点有深度的东西。二、什么是Objects在LVGL中&#xff0c;用户界面的 基本组成部分 是对象&#xff08;控件&#xff09;&#xff0c;也称为 Widgets。例如&#xff0c;一个 按钮、标签、图像、列表、图表 或者 文本区…

作者头像 李华
网站建设 2026/7/15 21:18:48

2026市面上目前靠谱的扫码点餐小程序服务商哪家专业好用?实测推荐

在餐饮行业竞争日益激烈的当下&#xff0c;扫码点餐小程序成为了众多商家提升服务效率、降低运营成本的利器。然而&#xff0c;市场上扫码点餐小程序服务商众多&#xff0c;让人眼花缭乱&#xff0c;究竟哪家才专业好用呢&#xff1f;今天&#xff0c;咱们就来实测推荐一番。用…

作者头像 李华
网站建设 2026/7/15 21:17:45

JDK 12 新特性详解

JDK 12 新特性详解 JDK 12 于 2019年3月19日 正式发布,是一个非 LTS(Non-LTS)版本。该版本引入了多个重要的语言特性预览(Switch 表达式、Pattern Matching),以及多项 JVM 和 GC 优化(G1 增强、ZGC 改进、Shenandoah GC 正式纳入)。JDK 12 为后续 LTS 版本(JDK 17)的…

作者头像 李华
网站建设 2026/7/15 21:15:35

Redis典型应用 - 分布式锁,引入过期时间,Lua脚本原子解锁操作,看门狗机制实现过期时间动态续约,Redlock算法

目录 什么是分布式锁&#xff1f; 多节点对共享资源的访问 分布式锁的基础实现 实现步骤引入过期时间引入校验机制引入 Lua 对 Lua 的介绍 引入看门狗 (watch dog) 两个时间概念具体例子注意点(对锁的续约时间理解) 引入 Redlock 算法 解决方案 什么是分布式锁? 多节点对…

作者头像 李华
网站建设 2026/7/15 21:15:05

新材料制造工业数据中台解决方案

某新材料制造型企业拥有多个生产厂房及自动化生产设备&#xff0c;涵盖配料、成型、切割、中涂、分色、包装等工艺流程。为全面推进数字化转型&#xff0c;企业计划构建数字化车间管理机系统&#xff0c;重点在于全面采集各工艺及产线设备数据&#xff0c;并实现对设备监控、故…

作者头像 李华