|最后更新: Invalid Date
📅 训练日期:2026-04-18
📊 今日正确率:42%(题目难度升级,概念框架已建立,细节待打磨)
🎯 核心收获:从"孤立名词"升级为"互相关联的认知网"

🗺️ 大厂数据链路全景图(一切的起点)

把今天所有概念放在一张图里,这是今后看任何数据开发题的思维地图
💡 类比:SQL 是订单,Catalyst 是菜谱设计师,RDD 是菜谱本身,Spark 是厨师,Hive Metastore 是菜单管理员,YARN 是调度员,HDFS 是冰箱。
🔗 各组件之间的精确关系
关系
含义
Catalyst → RDD
Catalyst 的最终产出就是 RDD DAG
Catalyst → Hive Metastore
Catalyst 在 Analyze 阶段去 Metastore 查字段类型
Hive Metastore ↔ Hive SQL 引擎
两者可分开使用;Spark 只借用 Metastore
RDD ↔ DataFrame
DataFrame 底层还是 RDD,只是多了 Schema
Spark ↔ Hadoop
Spark 借用 Hadoop 的 HDFS + YARN,但用自己的计算引擎替代 MapReduce
DAG ↔ Stage ↔ Task
DAG 按宽依赖切 Stage,一个 Stage 包含多个并行 Task

1️⃣ 四大天王:Hadoop / MapReduce / Hive / Spark

🧩 Hadoop:大数据基础设施"全家桶"
Hadoop 不是一个软件,是一套系统。
组件
职责
类比
HDFS
分布式存储
超大号冰箱,分布在多个仓库
YARN
资源调度
厨房调度员
MapReduce
计算引擎
老式厨师
🎯 关键认知:别人说"用 Hadoop",99% 是指 HDFS + YARN + 某种计算引擎(可能是 MR 也可能是 Spark)。
🐢 MapReduce:最老的计算引擎(被淘汰中)
核心流程:Map → Shuffle → Reduce
三大痛点:
  1. 中间结果必须写磁盘(I/O 重)
  1. 迭代算法灾难(机器学习跑不动)
  1. API 难写(WordCount 需要 200 行 Java)
现状: 新项目基本不用了,但笔试超高频(原理题的经典出处)。
🐘 Hive:SQL 翻译器 + 元数据管理
Hive 其实包含两个可独立使用的模块:
模块
职责
现状
Hive SQL 引擎
把 SQL 翻译成 MR/Tez/Spark 作业
越来越边缘化
Hive Metastore
管元数据(表、字段、分区、HDFS 路径)
大厂事实标准
🎯 关键认知:Hive 不存数据!数据存在 HDFS,Hive 只是"帮你管表" + "翻译 SQL"。
⚡ Spark:新一代计算引擎(主流)
Spark 比 MapReduce 快在哪?(必背 4 点)
  1. 内存计算:中间结果优先内存
  1. DAG 调度:整体优化,不是死板的两阶段
  1. 算子丰富:80+ 算子,MR 只有 map/reduce
  1. 线程级并行:Task 是线程,MR 是进程
⚠️ 陷阱:别说"Spark 纯内存"——内存不够照样落盘,Shuffle 一定落盘。
Spark 生态包含:
  • Spark Core(RDD)
  • Spark SQL(结构化数据)
  • Spark Streaming(流处理)
  • MLlib(机器学习)
  • GraphX(图计算)
⚠️ Spark on Hive vs Hive on Spark(超高频陷阱题)
名称
主角
SQL 引擎
元数据
执行
Spark on Hive ⭐大厂主流
Spark
Spark Catalyst
Hive Metastore
Spark
Hive on Spark
Hive
Hive SQL 引擎
Hive Metastore
Spark
🎯 一句话记忆:Spark 瞧不上 Hive 的 SQL 引擎(自己的 Catalyst 更强),但离不开 Hive 的 Metastore(元数据事实标准)。

2️⃣ Spark 不是数仓!厘清概念边界

📚 Spark / 数仓 / SQL / 存储 的精确定位
层次
代表
职责
存储层
HDFS / S3
存数据
数仓层
Hive(分层建模 ODS/DWD/DWS/ADS)
组织数据的方法论
计算引擎
Spark / MR / Flink
算数据
查询语言
SQL
表达需求
🎯 关键认知
  • Spark ≠ 数仓。它只管算,不管存,也不管建模。
  • 数仓是方法论,具体产品是 Hive、MaxCompute 等。
  • SQL 是语言不是产品,同一段 SQL 在不同引擎里执行路径完全不同。
🔤 SQL 的本质:声明式语言
声明式:你只说"要什么",不说"怎么做"。
你没说:
  • 要不要用内存
  • 要不要 Shuffle
  • 怎么分区
"怎么做"是执行引擎(Spark/Hive/MySQL)的事
🎯 同一段 SQL 在不同引擎里被翻译成不同的物理计划
  • MySQL → 走 B+ 树索引
  • Hive → 翻译成 MR 作业
  • Spark → Catalyst 翻译成 RDD DAG
  • Flink → 翻译成流处理算子

3️⃣ Spark 核心概念(今日主菜)

3.1 RDD:Spark 的基础抽象

🧠 RDD 的本质:菜谱,不是菜
RDD = Resilient Distributed Dataset
  • Resilient(弹性):分区丢了能自动重算
  • Distributed(分布式):切成分区散在多台机器
  • Dataset(数据集)—— ⚠️ 这个词是翻译陷阱!
🎯 RDD 的真实身份不是数据集,是"如何得到数据集的计算描述"(菜谱,不是菜)。
关键认知 3 点:
  1. RDD 是分布式集合的抽象,里面能装任意对象(数字、字符串、字典、自定义类)
  1. 默认不持有数据,只是计算图;Action 触发执行,cache 触发物化
  1. 核心价值:让数据"分散并行处理",不是"合并处理"
      • ❌ 错:RDD 把数据合并起来算
      • ✅ 对:RDD 让 100 TB 数据留在 1000 台机器上各自算,必要时才汇总(Shuffle)
🏷️ RDD 五大特性(必背)
#
特性
说明
1
分区列表 Partitions
数据切成多个分区
2
计算函数 Compute
每个分区有自己的计算函数
3
依赖关系 Dependencies
RDD 之间有血缘(lineage)
4
分区器 Partitioner
KV RDD 才有(Hash / Range)
5
优先位置 Preferred Locations
数据本地性
口诀分区、计算、依赖、分区器、位置
🎯 容错机制:基于 lineage 重算,不需要存多副本。
🏪 RDD 的类比:跨国连锁超市
你是总部,全球 1000 家门店,每家 10 万件库存。
  • 每家门店 = 一个分区(Partition)
  • 店员数自己店的货 = 窄依赖操作(map/filter)
  • 门店汇总数上报总部 = Shuffle(宽依赖)
  • 整个库存系统 = 一个 RDD
🎯 核心思想:RDD 不是把数据合并到一起算,而是让数据散着算——这是它能处理 PB 级数据的根本原因。

3.2 Schema:一切优化的前提

📋 Schema 是什么,为什么关键
Schema = 对数据结构的描述(字段名 + 类型)
无 Schema
有 Schema
数据样子
一堆字节/对象
带表头的表格
访问字段
x[2](靠下标)
df.age(靠字段名)
类型处理
手动 int()
自动
Spark 能否优化
❌ 不能
能(Catalyst)
🎯 一句话定位Schema 是 Spark 能做所有性能优化的前提。

3.3 RDD / DataFrame / Dataset:层层包装关系

🎂 三者不是替代关系,是三层蛋糕
对比表(必背):
维度
RDD
DataFrame
Dataset
Schema
类型检查
运行时
运行时
编译时
优化器
Catalyst
Catalyst
Python 支持
没有
性能
🎯 实战结论
  • 99% 用 DataFrame / Spark SQL
  • Python 没有 Dataset,不用纠结
  • DataFrame 底层最终还是 RDD
⚠️ 关于 DataFrame 比 RDD 快的陷阱
错误认知:"DataFrame 用内存,RDD 用磁盘"
正确认知:DataFrame 快是因为:
  1. Schema → Catalyst 优化(谓词下推、列裁剪等)
  1. Tungsten 内存优化(紧凑二进制格式,比 JVM 对象省一半内存)
  1. Whole-stage Codegen(多个算子编译成一个函数)

3.4 Catalyst:Spark SQL 的大脑

🧠 Catalyst 的四阶段工作流程(必背)
阶段
做的事
报错时机
Parse
SQL → 语法树
语法错
Analyze
查 Hive Metastore,绑定表/字段/类型
字段不存在
Optimize
RBO + CBO 优化
-
Physical Plan
选择具体执行方式(Join 策略等)
-
🎯 口诀解析 → 分析 → 优化(⭐最核心的一步) → 物理计划
🔧 RBO vs CBO 两大优化策略
RBO(规则优化)
CBO(成本优化)
依据
预设规则
表的真实统计信息
前提
需先 ANALYZE TABLE
例子
谓词下推、列裁剪
Join 顺序调整
常见优化规则:
  • 谓词下推:filter 推到数据源最近处
  • 列裁剪:只读用到的列
  • 分区裁剪:只扫用到的分区
  • 常量折叠10+8 编译期变成 18
🎯 Catalyst 只对 DataFrame/SQL 有效,对 RDD 无效——这是"用 DataFrame 不用 RDD"的根本原因。

3.5 宽依赖 vs 窄依赖

📐 定义与算子分类
  • 窄依赖:父 RDD 一个分区 → 子 RDD 最多一个分区使用(一对一)
  • 宽依赖:父 RDD 一个分区 → 子 RDD 多个分区使用(触发 Shuffle)
算子归类:
类型
算子
窄依赖
map, filter, flatMap, mapPartitions, union, coalesce(减少分区)
宽依赖
groupByKey, reduceByKey, distinct, sortByKey, repartition, join(默认)
⚠️ 5 个容易踩坑的陷阱
  1. union 是窄依赖(只拼分区不洗牌)
  1. coalesce 减少分区是窄依赖repartition 永远是宽依赖
  1. distinct 是宽依赖(底层是 reduceByKey
  1. join 不一定是宽依赖:预分区一致时是窄依赖(Co-partitioned Join)
  1. 窄依赖不触发 Shuffle

3.6 Shuffle:Spark 最大性能瓶颈

🌪️ Shuffle 是什么,为什么慢
定义:跨节点重新分发数据的过程。宽依赖必然触发 Shuffle。
两阶段:
  1. Shuffle Write:上游 Task 按 key 分桶写本地磁盘
  1. Shuffle Read:下游 Task 通过网络从各上游拉数据
4 大开销:
  1. 磁盘 I/O
  1. 网络 I/O
  1. 序列化/反序列化
  1. 容易数据倾斜
🛡️ 减少 Shuffle 的 5 个方法
  1. reduceByKey 代替 groupByKey(Map 端预聚合)
  1. 广播小表(Broadcast Join)
  1. 合理设置 spark.sql.shuffle.partitions(默认 200)
  1. 避免重复 Shuffle
  1. 预分区数据(Bucketed Join)

3.7 Map 端预聚合(Day 2 补讲)

🎯 为什么 reduceByKey 比 groupByKey 快
核心:Shuffle 前每个分区先局部聚合,减少 Shuffle 数据量。
对比示例(3 分区求每个 user 的 amount 总和):
方式
Shuffle 数据
原因
groupByKey().mapValues(sum)
全部原始记录
无预聚合
reduceByKey(_+_)
预聚合后结果
Map 端先局部合并
为什么 groupByKey 不能预聚合?
因为它只说"分组",没给聚合函数。reduceByKey 给了聚合函数,Spark 才能在本地提前聚合。
🌍 类比:全国人口普查
  • groupByKey:14 亿人全送北京再数 → 14 亿人在路上
  • reduceByKey:每村 → 每县 → 每省逐级汇总 → 只有 34 个数字送北京
🎯 死规则能用 reduceByKey 绝不用 groupByKey

3.8 懒执行(Lazy Evaluation)⭐今日重点

😴 什么是懒执行
定义:Transformation 算子调用时只记录逻辑(构建 DAG),不立刻执行;遇到 Action 时才一次性触发。
日常类比
  • 急性子助理(急切执行):每吩咐一句立刻跑一趟,跑 6 趟
  • 聪明助理(懒执行):攒到最后一次性规划 + 执行,只跑 1 趟
🎯 核心价值:攒着一起看才能做 Catalyst 全局优化(谓词下推、列裁剪)。
🔍 如何判断代码是不是懒执行(实战技巧)
判断法:看返回值类型
返回类型
判断
DataFrame / RDD
🟢 懒(Transformation)
具体值(int/list/None)
🔴 Action
打印到屏幕 / 写文件
🔴 Action
必背 Action 清单(就这些,其他全是懒的):
DataFrame:
RDD:
🎯 识别口诀能让数据离开 Spark 的就是 Action;只在 Spark 内部变形的就是 Transformation。
⚠️ 懒执行的 5 个关键推论
  1. 代码不报错不代表没错:错误等 Action 触发才暴露
  1. 打印 DataFrame 啥也看不到:只显示 Schema,要 show() 才显示数据
  1. 每次 Action 都从头重算:文件会被重复读(→ 用 cache()
  1. cache() 本身也是懒的:第一个 Action 触发时才真正物化
  1. 测时间要包到 Action 里:不然测到的是 0.001 秒(骗你的)

3.9 Cache / Persist(缓存)

💾 cache vs persist 使用指南
为什么要缓存?
用 cache 后:
常见存储级别:
级别
说明
MEMORY_ONLY
纯内存,放不下丢(cache 默认)
MEMORY_AND_DISK
内存不够放磁盘 ⭐生产常用
DISK_ONLY
只落盘
🎯 陷阱
  • cache() = persist(MEMORY_ONLY) 的简写
  • cache() 本身是懒的
  • 用完记得 unpersist()

3.10 Job / Stage / Task 四层级

🏗️ Spark 执行单元的嵌套关系
核心规则:
  • 1 个 Action = 1 个 Job
  • Stage 划分:从后往前扫 DAG,遇宽依赖就切
  • Stage 的 Task 数 = 该 Stage 最后一个 RDD 的分区数
  • 同一 Stage 内窄依赖算子合并成 pipeline 一气呵成
📊 为什么要切 Stage
宽依赖前后数据布局不同(key 重新分区了),不能在同一个 Task 里连续跑。必须切断:
  • Stage 内部:数据流水线,不落盘
  • Stage 之间(宽依赖处):Shuffle,落盘
🎯 这就是 Spark 比 MR 快的核心:MR 每步都落盘;Spark 只在 Stage 间落盘。

3.11 DAG 调度

🔗 DAG 是什么
DAG = Directed Acyclic Graph(有向无环图)
  • Directed:每条线有方向
  • Acyclic:不能有环
  • Graph:节点 + 边
Spark 把整个作业画成一张 DAG:
  • 节点 = 计算步骤
  • 边 = 数据流向
两大调度器:
角色
职责
DAGScheduler
按宽依赖把 DAG 切成 Stage
TaskScheduler
把 Task 分配给 Executor
🎯 DAG + 懒执行 + Catalyst,三者共同构成 Spark 快于 MR 的底层原理。

3.12 Join 策略(必考)

🤝 三种 Join 策略对比
策略
原理
适用
是否 Shuffle
BroadcastJoin
小表广播到每台机器
小表 < 几百 MB
✅ 无 Shuffle
SortMergeJoin
两表按 key 排序后合并
大表 vs 大表
ShuffleHashJoin
Shuffle 后建 Hash 表
中等规模
🎯 Catalyst 自动选
  • 一表很小 → BroadcastJoin
  • 两表都大 → SortMergeJoin
优化建议:
  • 开启 AQE(Spark 3.0+ 运行时自适应优化)
  • 提前分桶(Bucketed Join 免 Shuffle)
  • 调大 spark.sql.shuffle.partitions

3.13 数据倾斜基础(Day 3 深入)

⚖️ 数据倾斜识别与应对
症状:
  • 少数 Task 远慢于其他 Task(99% Task 1 分钟,1% Task 1 小时)
  • 作业卡尾部
  • OOM
常见场景:
  1. 爆款商品占订单 50%
  1. null / 默认值大量存在
  1. 热点地区 / 时段
应对方法:
  1. 过滤 null / 异常值
  1. 加盐:给倾斜 key 加随机前缀打散
  1. Map 端聚合(reduceByKey)
  1. 广播小表
  1. 倾斜 key 单独处理

4️⃣ Day 1 错题巩固

📅 拉链表 SQL 边界(错点 ①②)
🎯 记死三件套:<= + >= + 9999-12-31
🎯 事实表 vs 维度表(错点 ③)
3 把尺子:
维度
事实表
维度表
一行代表
一次事件
一个实体
字段
度量值 + 外键 id
描述性属性
时间
强时间戳
变化
只增
慢变
关键认知:
  • "描述谁" ≠ 维度表。维度描述实体属性,事实记录发生了什么
  • 名字带 "detail" 的大概率是事实表("明细" = 最细粒度事实)
  • 带一堆 xxx_id + 度量值的是事实表典型长相
📝 数仓术语精度(错点 ⑤)
三层词汇不能混:
层次
例子
原始事实字段
quantity, price
派生指标
gmv = price × quantity
聚合指标
order_cnt = count(*)
❌ 不要说"事实加维度"(数仓无此概念)
✅ 说"聚合事实表"(度量被聚合后的产物)

5️⃣ Day 2 错题复盘

❌ Q3:Action / Job / Cache 联动(错得典型)
原代码:
正确答案:
  • 读文件次数:1 次(cache 生效后,后两个 Action 用缓存)
  • Job 数:3 个(每个 Action 一个 Job)
  • cache 生效时机r1 = df3.count() 第一个 Action 触发时
  • 无 cache 情况:读 3 次(每个 Action 从头重算)
🎯 核心概念
  • 1 Action = 1 Job
  • 不 cache → 每个 Action 从头重算
  • cache 是懒的,第一个 Action 触发才真正物化
❌ Q5:Map 端预聚合(Claude 漏讲了)
版本 AgroupByKey().mapValues(sum) ❌ 慢
版本 BreduceByKey(_+_) ✅ 快
原因:B 有 Map 端预聚合,Shuffle 数据量小得多。
🎯 死规则:能用 reduceByKey 绝不用 groupByKey
❌ Q7:大表 Join 大表(完全没答)
场景:100 GB + 10 TB 按 user_id join
策略:SortMergeJoin(BroadcastJoin 装不下 100 GB)
代码
优化方向
  1. 开启 AQE
  1. 提前按 user_id 分桶
  1. 调大 shuffle 分区数
❌ Q8:TopN SQL(SQL 写错 3 处)
错点
  1. PARTITION BY user_id 错 → 应该是 PARTITION BY dt
  1. 多余逗号语法错
  1. 漏了 WHERE rank <= N
TopN 固定模板(死记):
三要素:
  1. PARTITION BY = "每个 X" 里的 X
  1. ORDER BY ... DESC = 排序依据
  1. 外层 WHERE rank <= N = 卡 TOP N

6️⃣ 我问过的好问题(知识点延伸)

❓ "order_detail 描述 order,为什么不是维度表?"
:维度表的"描述"是描述实体属性(长啥样),事实表记录发生了什么(业务事件)。
  • order_detail 记录"某用户某时刻买了某商品" → 是事件 → 事实表
  • dim_order(假想)描述"订单类型、渠道、是否礼品订单" → 是属性 → 维度表
🎯 判断口诀:看字段不看名字。有 price、quantity 就是度量,就是事实表。
❓ "Spark 是数据仓库吗?"
:不是。Spark 是计算引擎,只负责"算",不负责"存"。
层次
代表
存储
HDFS
数仓
Hive
计算
Spark
语言
SQL
🎯 大厂组合:Spark on Hive(Spark 计算 + Hive 元数据 + HDFS 存储)
❓ "SQL 扮演什么角色?"
:SQL 是一种声明式语言(只说要什么,不说怎么做),不是一个产品。
  • 同一段 SQL 可以给 MySQL / Hive / Spark / Flink 执行
  • 各引擎解析 + 执行路径完全不同
  • 它是"人与引擎之间的翻译层"
🎯 类比:SQL 是菜单上的菜名,不同餐厅(MySQL / Spark)做出来味道不同。
❓ "RDD 是数据集吗?"
:严格讲不是。RDD 是"如何得到数据集的计算描述"(菜谱,不是菜)。
  • RDD 默认不持有数据
  • Action 触发执行时才真正计算
  • cache 时才真正物化到内存
🎯 翻译陷阱:中文"弹性分布式数据集"容易让人以为是装着数据的容器,其实它是计算图。
❓ "RDD 类似没 column 的 csv?能合并大量数据?"
前半句:直觉对,但不精确。
  • CSV 每行必须是结构化字段
  • RDD 每条可以是任意对象(数字、字典、自定义类)
  • 当 RDD 里恰好装 CSV 行字符串时,"给 CSV 加表头 = RDD → DataFrame" 这个类比成立
后半句:❌ 错。RDD 核心不是"合并",是"分散并行处理"。
  • 100 TB 数据留在 1000 台机器上各自算
  • 只在必要时(GroupBy/Join)才跨机器汇总(Shuffle,慢)
🎯 核心:RDD 不是把数据合起来算,而是让数据散着算。
❓ "Catalyst 又是什么?"
:Spark SQL 的"大脑",负责把 SQL / DataFrame 翻译 + 优化成能跑的执行计划。
4 阶段:Parse → Analyze → Optimize → Physical Plan
关键认知:Catalyst 只对 DataFrame / SQL 有效,对 RDD 无效。这就是"用 DataFrame 不用 RDD"的根本原因。
❓ "Hive 不是也有 SQL 引擎吗,怎么又说 Spark 用自己的?"
:Hive 有两个可独立模块:
  1. Hive SQL 引擎(翻译 SQL)
  1. Hive Metastore(管元数据)
Spark on Hive 只借用 Metastore,SQL 解析用自己的 Catalyst(更快)。
🎯 一句话:Spark 瞧不上 Hive 的 SQL 引擎,但离不开 Hive 的 Metastore。
❓ "懒执行到底是什么?怎么判断?"
懒执行:Transformation 只记录逻辑,Action 才触发执行。
判断法
  • 返回 DataFrame/RDD → 懒
  • 返回具体值 / 打印 / 写文件 → Action
必背 Actionshow, count, collect, take, first, foreach, write.xxx
🎯 口诀:能让数据离开 Spark 的就是 Action。

7️⃣ 今日核心概念关系网

🕸️ 所有概念的互联关系(必看)
主干线:
懒执行贯穿一切:
性能优化四件套:
容错链路:

8️⃣ Day 3 预告

📅 明天重点
基于今日暴露的问题,Day 3 将深入:
  1. Shuffle 原理深入 + 数据倾斜 7 大解法(承接 Q4)
  1. Join 策略完整剖析(承接 Q7)
  1. Job / Stage / Task 三层级深入(承接 Q3、Q6)
  1. SQL 窗口函数集训(承接 Q8,必须拿下)
  1. Spark 性能调优参数(笔试高频)

🎯 Day 2 三句话记忆

  1. 大数据技术栈分层:SQL → Catalyst → RDD → Spark → YARN → HDFS;每层各司其职,Spark 不是数仓,只是计算引擎。
  1. Spark 快于 MR 的三大支柱:懒执行(攒着一起优化)+ Catalyst(自动优化)+ DAG 调度(按宽依赖切 Stage,减少落盘)。
  1. 实战优先级:99% 用 DataFrame/SQL,不用 RDD;能用 reduceByKey 不用 groupByKey;多次用的 DataFrame 必须 cache;大表 Join 小表用 Broadcast。
Loading...