数据工程实战课程 · ETL基础阶段
数据提取是ETL第一步,负责从各种异构数据源中获取原始数据。优秀的提取策略需要平衡完整性、时效性和资源消耗。
| 数据源 | 提取方式 | 增量策略 |
|---|---|---|
| REST API | 分页请求 | 时间戳/游标 |
| 关系数据库 | SQL/CDC | 自增ID/时间列 |
| CSV/JSON | 文件读取 | 修改时间 |
# 数据库提取(SQLite实机)
import sqlite3, time, random
from datetime import datetime, timedelta
conn = sqlite3.connect(':memory:')
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute('CREATE TABLE orders (id INTEGER PRIMARY KEY AUTOINCREMENT, customer_id TEXT, amount REAL, status TEXT, region TEXT, created_at TIMESTAMP)')
regions = ['华东','华南','华北','西南','东北']
for i in range(1000):
c.execute("INSERT INTO orders VALUES (?,?,?,?,?,?)",
(None, f"客户_{random.randint(1,200)}", round(random.uniform(10,5000),2),
random.choice(['pending','shipped','delivered']), random.choice(regions),
(datetime.now()-timedelta(days=random.randint(0,30))).isoformat()))
conn.commit()
print(f"测试库: 1000订单")
# 全量提取
start = time.perf_counter()
rows = [dict(r) for r in c.execute("SELECT * FROM orders").fetchall()]
print(f"全量: {len(rows)}条, {(time.perf_counter()-start)*1000:.2f}ms")
# 增量提取(id>990)
start = time.perf_counter()
rows = [dict(r) for r in c.execute("SELECT * FROM orders WHERE id > 990").fetchall()]
print(f"增量(id>990): {len(rows)}条, {(time.perf_counter()-start)*1000:.2f}ms")
# 并行提取(4分区)
for s,e in [(1,250),(251,500),(501,750),(751,1000)]:
rows = c.execute("SELECT COUNT(*) FROM orders WHERE id BETWEEN ? AND ?", (s,e)).fetchone()[0]
print(f" 分区[{s},{e}]: {rows}条")
print("✅ 验证通过 - 数据库提取运行正常")
| 策略 | 场景 | 提升 |
|---|---|---|
| 并行提取 | 多数据源 | 2-8x |
| 增量替代全量 | 大数据低变更 | 10-100x |
| 谓词下推 | 分区+过滤 | 5-50x |
# 文件提取:CSV/JSON
import csv, json, io, random
class FileExtractor:
def extract_csv(self, content, delimiter=','):
reader = csv.DictReader(io.StringIO(content), delimiter=delimiter)
return [dict((k, float(v) if v.replace('.','',1).isdigit() else v.strip())
for k,v in row.items() if v.strip()) for row in reader]
def extract_json(self, content):
data = json.loads(content)
if isinstance(data, list): return data
for key in ['data','records','items']:
if key in data and isinstance(data[key], list): return data[key]
return [data]
csv_content = "id,name,amount,category\n"
for i in range(1, 51):
csv_content += f"{i},商品_{i},{round(random.uniform(10,500),2)},{random.choice(['A','B','C'])}\n"
json_content = json.dumps({'data':[
{'id':i,'sensor':f"sensor_{random.randint(1,20)}",'value':round(random.uniform(0,100),2)}
for i in range(1,31)]}, ensure_ascii=False)
ext = FileExtractor()
csv_r = ext.extract_csv(csv_content)
json_r = ext.extract_json(json_content)
print(f"CSV: {len(csv_r)}条, JSON: {len(json_r)}条")
print(f"CSV示例: {csv_r[0]}")
print("✅ 验证通过 - 文件提取运行正常")
🎁 下一课预告:数据转换!
| 优化项 | 方法 | 预期效果 |
|---|---|---|
| I/O优化 | 批量读写、列式存储、压缩 | 3-10x |
| 计算优化 | 向量化执行、谓词下推、列裁剪 | 2-5x |
| 并行化 | 分区并行、流水线并行 | 线性扩展 |
| 缓存 | 维度表缓存、结果缓存 | 2-10x |
| 增量处理 | 只处理变更数据 | 10-100x |
在生产环境中,我们经常遇到教科书不会告诉你的问题。以下是常见的实战经验和解决方案:
| 指标 | 告警阈值 | 监控方式 |
|---|---|---|
| 管道延迟 | 超过SLA 120% | 端到端时间戳追踪 |
| 数据量偏差 | 日均偏差超过30% | 与历史同期对比 |
| 错误率 | 超过0.1% | 错误计数/总记录数 |
| 数据新鲜度 | 超过SLA 150% | 最新数据时间戳 |
| 资源利用率 | CPU持续>80% | 系统监控 |
A: 根据业务延迟要求决定:秒级用流处理、分钟级用微批、小时级用批处理。大部分场景批处理足够,流处理用于实时业务场景(风控、监控、推荐)。
A: 不会完全取代,但边界在模糊。湖仓一体(如Iceberg/Delta Lake)正在融合两者优势。未来趋势是统一存储+多引擎计算。
A: 先用云原生服务(BigQuery/Snowflake + Fivetran + dbt + Looker),验证业务后再考虑自建。过早优化是万恶之源。
A: 用钱说话:数据质量问题的直接经济损失(错误决策、合规罚款、重复劳动)远大于治理投入。量化问题是第一步。
| 角色 | 职责 | 交付物 |
|---|---|---|
| 数据工程师 | 管道开发与维护 | 数据管道、基础设施 |
| 数据分析师 | 数据分析与报表 | SQL查询、BI报表 |
| 数据科学家 | 模型与实验 | ML模型、实验报告 |
| 数据产品经理 | 需求与优先级 | PRD、数据产品规划 |
| 数据管家 | 数据质量与治理 | 质量规则、数据字典 |