第六章 数据加载策略:全量加载、增量加载与SCD处理
数据加载,说白了就是把处理好的数据写进目标系统。这一步看似简单,但坑特别多。我见过不少团队,ETL跑得飞快,结果加载环节频频翻车——不是性能崩了,就是数据对不上。
这一章,咱们就聊聊加载策略的那些事。我会结合自己踩过的坑,把全量加载、增量加载、SCD处理以及性能优化这些核心内容讲透。
6.1 全量加载:简单粗暴,但别滥用
全量加载,就是每次把源表的所有数据全部覆盖到目标表。实现起来最简单:
-- 全量加载示例(PostgreSQL)
TRUNCATE TABLE target_schema.sales;
INSERT INTO target_schema.sales
SELECT * FROM source_schema.sales;
嗯,这里要注意——全量加载虽然代码简单,但代价很高。我曾在某电商项目里,每天全量加载一张5亿行的订单表,结果ETL窗口从2小时膨胀到8小时,最后不得不重构。
什么时候用全量加载?
- 数据量小(百万级以下)
- 目标表需要完全重建(比如维度表重构)
- 源系统不支持增量识别
6.2 增量加载:高效但需要技巧
增量加载只处理新增或变化的数据。核心思路就两个:
- 基于时间戳:源表有最后修改时间字段
- 基于CDC:通过日志捕获变更
我个人习惯用时间戳方式,简单可靠。但要注意——源表的时间戳字段必须有索引,否则你会哭的。
-- 增量加载示例(基于时间戳)
INSERT INTO target_schema.sales
SELECT * FROM source_schema.sales
WHERE last_modified > (
SELECT COALESCE(MAX(last_loaded), '1970-01-01')
FROM target_schema.load_control
WHERE table_name = 'sales'
);
6.3 Merge/Upsert:增量更新的核心
增量加载不只是INSERT,还要处理更新。这时候就需要Merge(也叫Upsert)。
说白了,Merge就是:存在就更新,不存在就插入。不同数据库语法略有差异:
-- PostgreSQL的Merge语法
MERGE INTO target_schema.sales AS t
USING source_schema.sales AS s
ON t.order_id = s.order_id
WHEN MATCHED THEN
UPDATE SET
amount = s.amount,
last_modified = CURRENT_TIMESTAMP
WHEN NOT MATCHED THEN
INSERT (order_id, amount, last_modified)
VALUES (s.order_id, s.amount, CURRENT_TIMESTAMP);
你想想看,如果没有Merge,你得先查一遍判断是否存在,再决定INSERT还是UPDATE。不仅代码啰嗦,性能也差。
6.4 SCD(缓慢变化维)处理
SCD是维度建模里的经典问题。说白了就是:维度表的属性会变,你怎么处理历史数据?
常见的三种类型:
| 类型 | 处理方式 | 适用场景 |
|---|---|---|
| SCD Type 1 | 直接覆盖旧值 | 不关心历史变化(如用户手机号) |
| SCD Type 2 | 保留多条记录,加生效时间 | 需要追溯历史(如产品分类) |
| SCD Type 3 | 增加字段存旧值 | 只关心上一次变化 |
我在项目中用得最多的是Type 2。实现起来也不复杂:
-- SCD Type 2 实现示例
-- 先关闭旧记录
UPDATE dim_customer
SET is_active = FALSE,
end_date = CURRENT_DATE - 1
WHERE customer_id = 123
AND is_active = TRUE;
-- 再插入新记录
INSERT INTO dim_customer (
customer_id, name, city,
start_date, end_date, is_active
)
VALUES (
123, '张三', '北京',
CURRENT_DATE, '9999-12-31', TRUE
);
6.5 加载性能优化
加载性能优化,我总结了几个核心原则:
- 批量提交:别一条一条INSERT,用批量操作。我习惯每1000条提交一次。
- 关闭约束和索引:加载前禁用索引和外键,加载完再重建。能快5-10倍。
- 并行加载:按分区或分片并行写入。但要注意目标库的连接数限制。
- 使用原生加载工具:比如PostgreSQL的COPY、MySQL的LOAD DATA INFILE,比INSERT快一个数量级。
-- PostgreSQL COPY命令示例(比INSERT快10倍)
COPY target_schema.sales
FROM '/data/sales_20240101.csv'
DELIMITER ','
CSV HEADER;
6.6 知识体系总览
下面这张图,是我对本章知识体系的总结。你可以把它当作一个快速索引:
这张图把本章的核心内容串起来了。你想想看,实际项目中往往不是只用一种策略,而是组合使用。比如:维度表用SCD Type 2,事实表用增量Merge,小表用全量加载。
核心总结:
- 全量加载:简单但成本高,适合小表或重建场景
- 增量加载:高效但需要源系统支持
- Merge/Upsert:增量更新的标准做法
- SCD:维度变化的历史管理方案
- 性能优化:批量、关闭约束、并行、原生工具
好了,这一章的内容就到这里。加载策略选对了,ETL就成功了一半。剩下的,就是多测试、多踩坑、多总结。
公众号:蓝海数据掘金营,微信deep3321