Spark SQL CACHE TABLE 详解

Spark SQL CACHE TABLE 详解

一、语法

sql 复制代码
-- 1. 缓存已存在的表/视图
CACHE TABLE table_name;

-- 2. 缓存查询结果为临时表
CACHE TABLE table_name AS SELECT ...;

-- 3. 懒加载(首次查询时才缓存)
CACHE LAZY TABLE table_name AS SELECT ...;

二、缓存原理

复制代码
┌─────────────────────────────────────────────────────────┐
│                    SparkSession                          │
│  ┌─────────────────────────────────────────────────┐    │
│  │              CacheManager                        │    │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐         │    │
│  │  │ Table A │  │ Table B │  │ Table C │         │    │
│  │  │ (缓存)  │  │ (缓存)  │  │ (缓存)  │         │    │
│  │  └─────────┘  └─────────┘  └─────────┘         │    │
│  └─────────────────────────────────────────────────┘    │
│                         ↓                                │
│  ┌─────────────────────────────────────────────────┐    │
│  │              Executor 内存                       │    │
│  │    BlockManager (实际存储缓存数据)              │    │
│  └─────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘

缓存流程:

  1. 执行查询生成 DataFrame
  2. 将 DataFrame 注册到 Session 的 CacheManager
  3. 触发 Action(非 LAZY 模式立即触发)将数据缓存到 Executor 内存

三、缓存级别

级别 说明 适用场景
MEMORY_ONLY 仅内存,内存不足时分区丢失 小数据集,内存充足
MEMORY_AND_DISK 内存优先,不足时溢写到磁盘 Spark SQL 默认,通用场景
DISK_ONLY 仅磁盘 大数据集,内存紧张
MEMORY_ONLY_SER 内存+序列化,节省空间 内存紧张但 CPU 有余
OFF_HEAP 堆外内存 需避免 GC 影响

SQL 限制CACHE TABLE 默认 MEMORY_AND_DISK,不可自定义。

DataFrame API 可自定义

scala 复制代码
df.persist(StorageLevel.MEMORY_ONLY)

四、LAZY vs 非 LAZY

sql 复制代码
-- 非懒加载:立即执行查询并缓存
CACHE TABLE tmp AS SELECT * FROM big_table WHERE dt='2026-07-01';
-- ↑ 执行计划立即触发,数据加载到内存

-- 懒加载:仅记录缓存意向,首次查询时才缓存
CACHE LAZY TABLE tmp AS SELECT * FROM big_table WHERE dt='2026-07-01';
-- ↑ 此时什么都不做

SELECT * FROM tmp;  -- 这里才真正缓存

选择建议

  • 确定会用 → CACHE TABLE(立即加载)
  • 可能不用 → CACHE LAZY TABLE(按需加载)

五、作用域与生命周期

复制代码
┌────────────────────────────────────────────────┐
│              Spark Application                  │
│  ┌──────────────┐      ┌──────────────┐       │
│  │ Session A    │      │ Session B    │       │
│  │ ┌──────────┐ │      │ ┌──────────┐ │       │
│  │ │ cache_t1 │ │      │ │ cache_t1 │ │       │
│  │ │ (独立)   │ │      │ │ (独立)   │ │       │
│  │ └──────────┘ │      │ └──────────┘ │       │
│  └──────────────┘      └──────────────┘       │
│         ↓                      ↓               │
│    Session 关闭            Session 关闭        │
│    缓存自动释放            缓存自动释放        │
└────────────────────────────────────────────────┘
特性 说明
作用域 Session 级别,不同 Session 隔离
生命周期 Session 存活期间有效
释放时机 Session 关闭 / UNCACHE TABLE / CLEAR CACHE
跨 Session 不共享,同名表互不影响

六、常用操作

sql 复制代码
-- 1. 缓存表
CACHE TABLE tmp AS
SELECT waybill_code, status, update_time
FROM app.test;

-- 2. 查看缓存状态
DESCRIBE EXTENDED tmp;
-- 输出中查找: Is Cached: true

-- 3. 解除单个缓存
UNCACHE TABLE tmp;

-- 4. 清除所有缓存
CLEAR CACHE;

七、实际应用场景

场景1:维表重复关联

sql 复制代码
-- 小维表被多次关联,缓存避免重复扫描
CACHE TABLE dim_region;
CACHE TABLE dim_status;

SELECT a.*, r.region_name, s.status_name
FROM fact_order a
JOIN dim_region r ON a.region_id = r.id
JOIN dim_status s ON a.status = s.code;

SELECT a.*, r.region_name
FROM fact_order_detail a
JOIN dim_region r ON a.region_id = r.id;

场景2:中间结果复用

sql 复制代码
-- 中间结果被多次引用
CACHE TABLE tmp_filtered AS
SELECT * FROM big_table WHERE dt = '2026-07-01' AND status IN (1, 31);

-- 后续多次查询直接走内存
SELECT COUNT(*) FROM tmp_filtered WHERE status = 1;
SELECT COUNT(*) FROM tmp_filtered WHERE status = 31;
SELECT waybill_code FROM tmp_filtered LIMIT 100;

场景3:迭代计算

sql 复制代码
-- 机器学习/图计算迭代场景
CACHE TABLE graph_nodes AS SELECT * FROM nodes;

-- 多轮迭代读取同一份数据
-- 第1轮
SELECT /*+ BROADCAST(graph_nodes) */ ... FROM graph_nodes;
-- 第2轮
SELECT /*+ BROADCAST(graph_nodes) */ ... FROM graph_nodes;

八、注意事项

问题 说明 解决方案
内存溢出 缓存过多导致 OOM 控制缓存数据量,及时 UNCACHE
数据过期 源表更新后缓存未刷新 手动 UNCACHE 后重新 CACHE
占用 Executor 内存 影响其他任务执行 评估内存容量,选择合适数据集
小文件问题 缓存表有小文件 缓存前 REPARTITION
重复缓存 同一表多次 CACHE 无效 Spark 会检查是否已缓存

九、性能调优建议

sql 复制代码
-- 1. 缓存前优化文件数
CACHE TABLE tmp AS
SELECT /*+ REPARTITION(100) */ * FROM big_table;

-- 2. 只缓存需要的列
CACHE TABLE tmp AS
SELECT col1, col2, col3 FROM big_table;  -- 不要 SELECT *

-- 3. 及时释放
UNCACHE TABLE tmp;  -- 用完及时释放

十、与 Hive Metastore 的区别

对比项 CACHE TABLE CREATE TABLE
存储位置 Executor 内存 HDFS/S3
作用域 Session 级别 全局(Metastore)
持久性 Session 结束即消失 永久保存
跨 Session 不可见 所有 Session 可见
同名冲突 不同 Session 不冲突 全局冲突

十一、总结

  • CACHE TABLE = 内存缓存 + Session 隔离
  • 默认级别 = MEMORY_AND_DISK
  • 适用场景 = 维表关联、中间结果复用、迭代计算
  • 核心原则 = 够用即可,用完释放