当前位置: 首页 > news >正文

Spark专题-第二部分:Spark SQL 入门(2)-算子介绍-Scan/Filter/Project

第二部分:Spark SQL 入门(2)-算子介绍-Scan/InMemoryTableScan

其实在开始这部分之前,我思考了很久,到底该如何把算子教给读者,如果按其他的教学文章,应该会挨个罗列并展示用途,但我就自己学习经验来说,这种方式似乎并不高效,于是我打算把算子和sql联系起来,尽量避免抽象,如果各位有什么好的建议,请不吝赐教

1. HiveTableScan-数据扫描算子

我相信各位读者对这种sql应该不会觉得困难,当然了,实际工作中就别写*了,我这里偷个懒,需要哪些字段就写哪些字段,尽量减少查询的负担,能更快一些

SELECT * FROM tableA;

而这句最简单的select语句其实通过spark ui查看的话,就会是下面这张图,实际的表名和字段名都粗暴打码,不影响查看算子
在这里插入图片描述

//底层实际上会生成如下类型的扫描节点
val scan = sparkSession.sql("SELECT * FROM tableA")
//执行计划中会显示为:
//HiveTableScan [col1#0L, col2#1, ...], HiveTableRelation ...

说明

  • 用于从 Hive 表中读取数据
  • 显示所有选中字段(包括分区字段)
  • 对应 `DataSourceScanExec` 或 `HiveTableScanExec` 物理算子

2. InMemoryTableScan-内存查询算子

但其实select语句还可能对应 InMemoryTableScan 阶段:
在这里插入图片描述

// 如果该表已被缓存或物化,可能会触发内存扫描
val df = spark.table("tableA")
df.cache() // 或 persist()
df.select("*").explain()
// 执行计划中会出现:
// InMemoryTableScan [col1#0L, col2#1, ...]

说明

  • 表示从 Spark 内存中读取缓存数据
  • 通常出现在查询已被缓存(`cache()`/`persist()`)的表时
  • 可显著提升查询性能,避免重复读取外部数据

对比:HiveTableScan vs InMemoryTableScan

特性HiveTableScanInMemoryTableScan
数据源Hive 外部表Spark 内存数据
IO 开销磁盘/网络 IO内存访问
执行速度较慢 (13s)较快 (1s)
字段处理全字段扫描选择性字段扫描
使用场景初始数据加载缓存数据重用

3. Filter - 数据过滤算子

SELECT [部分字段]
FROM tabelB
WHERE day = '20250917' AND [其他过滤条件]

在这里插入图片描述

功能与性质

  • 条件过滤:根据WHERE子句中的条件过滤数据行
  • 谓词下推:尽可能在数据扫描阶段提前执行过滤
  • 选择率:过滤后保留的数据比例影响查询性能

执行详情

输入:671,768行(来自Scan阶段)
输出:569,329行
过滤率:约15.2%(过滤掉102,439行)

优化机制

  • 使用统计信息优化过滤顺序(高选择率条件优先)
  • 支持多种过滤条件(等于、范围、IN等)

4. Project - 字段裁剪算子

功能与性质

  • 字段选择:只选择查询中指定的列,减少数据传输量
  • 表达式计算:处理SELECT中的计算表达式和函数调用
  • 类型转换:处理数据类型的转换和格式化

优化机制

  • 消除不必要的字段传输
  • 合并多个投影操作
  • 延迟计算直到必要时

5. 完整执行流程

投影阶段
选择SELECT指定字段
执行计算表达式
类型转换
过滤阶段
应用WHERE条件
过滤不满足条件的行
Scan 阶段
读取Hive表数据
应用分区过滤
day=20250917
列裁剪
只读取需要的列
开始查询
输出: 671,768行
输出: 569,329行
过滤率: 15.2%
最终输出
查询完成

6. 性能优化建议

6.1 Scan优化

-- 使用分区过滤
WHERE day = '20250917'-- 使用列裁剪(只选择需要的列)
SELECT col1, col2 FROM table-- 使用合适的文件格式(如Parquet)

6.2 Filter优化

-- 将高选择率条件放在前面
WHERE high_selectivity_condition AND low_selectivity_condition-- 避免在过滤条件中使用复杂函数
WHERE date_column = '2025-09-18'  -- 好
WHERE DATE_FORMAT(date_column, 'yyyy-MM-dd') = '2025-09-18'  -- 差

6.3 Project优化

-- 只选择需要的字段
SELECT col1, col2 FROM table  -- 好
SELECT * FROM table  -- 差-- 避免在SELECT中使用复杂计算
SELECT simple_column FROM table  -- 好
SELECT complex_calculation(column) FROM table  -- 可能影响性能

7. 总结

通过两个简单的sql语句,了解了Spark SQL中的三个核心算子:

  1. Scan:负责从数据源读取数据,支持分区剪枝和列裁剪
  2. Filter:负责应用WHERE条件过滤数据行,支持谓词下推
  3. Project:负责选择最终输出的字段,支持表达式计算

希望这种将sql与算子对应起来的讲解方式,能更好的让读者理解,这一篇涉及的不论是sql还是算子都是基础款,后续会一点一点增加复杂程度

http://www.dtcms.com/a/389331.html

相关文章:

  • Selenium 自动化爬虫:处理动态电商页面
  • 无需Selenium:巧用Python捕获携程机票Ajax请求并解析JSON数据
  • Python版Kafka基础班 - 学习笔记
  • IDEA 查看 Maven 依赖树与解决 Jar 包冲突
  • 【LVS入门宝典】LVS与Nginx、HAProxy的对比:四层(LVS) vs 七层(Nginx)的适用场景
  • 系统安全配置与加固
  • 【AI-Agent】AI游戏库
  • 病毒库更新原理
  • 服务器内存爆炸,日志无报错,通过分析 Dump 文件查找问题原因
  • 【Redis学习】服务端高并发分布式结构演变之路
  • 【JavaScript 性能优化实战】第三篇:内存泄漏排查与根治方案
  • 关于JavaScript性能优化实战的技术
  • 分布式流处理与消息传递——Paxos Stream 算法详解
  • ​​瑞芯微RK3576多路AHD摄像头实测演示,触觉智能配套AHD硬件方案
  • mysql删除数据库命令,如何安全彻底地删除MySQL数据库?
  • vscode中创建项目、虚拟环境,安装项目并添加到工作空间完整步骤来了
  • 如何快速传输TB级数据?公司大数据传输的终极解决方案
  • Linux的进程调度及内核实现
  • 使用BeanUtils返回前端为空值?
  • Windows Server数据库服务器安全加固
  • Linux TCP/IP调优实战,性能提升200%
  • Amazon ElastiCache:提升应用性能的云端缓存解决方案
  • 查找并替换 Excel 中的数据:Java 指南
  • 多线服务器具体是指什么?
  • Golang语言基础篇001_常量变量与数据类型
  • pytest文档1-环境准备与入门
  • MySQL 专题(四):MVCC(多版本并发控制)原理深度解析
  • 【开发者导航】在终端中运行任意图形应用:term.everything
  • [Python]pytest是什么?执行逻辑是什么?为什么要用它测试?
  • Nginx set指令不能使用在http块里,可以使用map指令