Predicate Push Down(谓词下推)

Predicate Push Down(谓词下推)是把 WHERE 条件尽早应用,在数据扫描阶段就过滤掉不需要的数据,而不是先读出来再过滤。

例如SELECT * FROM orders WHERE order_date = '2024-01-01';

如果没有谓词下推:

Storage → 读取全部 1000 万行 → Compute → 过滤 → 返回 1 万行
          ────────────────
          大量无效 I/O

有谓词下推:

Storage → 只读取符合条件的 1 万行 → Compute → 返回 1 万行
          ─────────────────────
          I/O 大幅减少

下推到哪一层?

┌─────────────────┐
│   Leader Node   │  ← 解析 SQL,识别谓词
└────────┬────────┘
         │ 下推 WHERE 条件
         ▼
┌─────────────────┐
│  Compute Node   │  ← 谓词下推到这里
└────────┬────────┘
         │ 可能继续下推
         ▼
┌─────────────────┐
│     AQUA        │  ← 硬件加速过滤(RA3)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│    Storage      │  ← Zone Map 跳过不相关块
└─────────────────┘

Zone Map 举例

orders 表按 order_date 排序存储:

Block 1: order_date [2024-01-01 ~ 2024-01-10]  ← 扫描
Block 2: order_date [2024-01-11 ~ 2024-01-20]  ← 跳过
Block 3: order_date [2024-01-21 ~ 2024-01-31]  ← 跳过
Block 4: order_date [2024-02-01 ~ 2024-02-10]  ← 跳过

WHERE order_date = '2024-01-05'
→ Zone Map 告诉 Redshift 只有 Block 1 可能包含数据
→ 直接跳过 Block 2/3/4

查询 S3 外部表(Spectrum)时,谓词下推更重要:

-- 外部表 (S3 Parquet)
SELECT * FROM spectrum.logs WHERE log_date = '2024-01-01';
有无下推 行为
❌ 无 读取 S3 全部文件 → 网络传输 → 过滤
✅ 有 只读取 2024-01-01 分区的文件

查看是否下推

EXPLAIN SELECT * FROM orders WHERE order_date = '2024-01-01';

输出中看:

关键词 含义
Filter 在 Scan 里面 ✅ 谓词已下推
Filter 在 Scan 外面 ❌ 扫描后再过滤

最佳实践

建议 原因
用 SORTKEY 列做过滤 Zone Map 效果最好
避免函数包装列 无法下推
Spectrum 用分区 直接跳过不需要的 S3 文件
用列式格式 Parquet/ORC 支持列级下推
保持数据有序 VACUUM SORT 维护排序

总结

谓词下推是自动的,用户要做的是"让它更有效”—— 设好 SORTKEY、别用函数包列、保持数据有序。