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 跳过不相关块
└─────────────────┘
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、别用函数包列、保持数据有序。