Amazon Redshift 上的 Iceberg 物化视图

增量刷新 (Incremental Refresh) 技术深度指南 — 架构原理、完整实践、性能优化与注意事项

更新于 2026-07 Amazon Redshift Apache Iceberg Incremental Refresh

概述与核心价值

物化视图 (Materialized View, MV) 是 Amazon Redshift 的一项核心优化能力——它将复杂查询的结果预计算并持久化存储在 Redshift 本地,后续查询直接读取预计算结果,跳过昂贵的扫描和聚合。

自 2024 年 10 月 GA 起,Amazon Redshift 支持在 Apache Iceberg 外部表上创建物化视图,并支持增量刷新 (Incremental Refresh)——Redshift 能够利用 Iceberg 的 snapshot 机制,只读取自上次刷新后发生变化的数据,而非全表扫描,大幅降低刷新成本和时间。

13.5×
INSERT 后增量刷新平均加速比
15×
DELETE 后增量刷新平均加速比
43.8×
最大加速比 (INSERT 场景)

* 基准: AWS 官方 TPC-DS 3TB 测试,Iceberg CoW 模式,ra3.4xl × 4 节点,34 个物化视图,1% 数据变更

适用场景

架构原理

Compute 层 — Amazon Redshift

创建 MV、执行增量/全量刷新、存储预计算结果、响应分析查询

↕ Spectrum / 本地引擎读取变化数据
📋

Catalog 层 — AWS Glue Data Catalog

维护 Iceberg 表元数据、snapshot 列表、manifest 文件位置

↕ 读取 manifest & data files
🪣

Storage 层 — Amazon S3 / S3 Tables

存储 Iceberg 数据文件 (Parquet)、metadata.json、manifest list

增量刷新的工作机制

Iceberg 的 snapshot-based 事务管理是增量刷新的关键。当 Redshift 刷新 MV 时:

  1. 对比 Snapshot:Redshift 记录上次刷新时的 Iceberg snapshot ID,刷新时读取当前最新 snapshot
  2. 差异计算:通过对比两个 snapshot 之间的 manifest 差异,精确定位新增/删除/修改的 data files
  3. 增量读取:仅从 S3 读取变化的 data files(而非全表扫描)
  4. 本地更新:将增量数据合并到 Redshift 本地存储的 MV 数据中
关键区别:Copy-on-Write vs Merge-on-Read

Iceberg 的两种写模式都被支持:

  • Copy-on-Write (CoW):更新时重写整个数据文件。Redshift 对比 manifest 即可定位变化文件。
  • Merge-on-Read (MoR):更新时写入 delete files。Redshift 需读取 delete files + data files 合并处理。

两种模式均支持增量刷新,但 CoW 模式的增量刷新效率通常更高。

支持的操作与增量刷新范围

MV 创建(初始化)的增量支持

基表类型增量创建备注
Iceberg 表(分区/非分区)✅ 支持Copy-on-Write & Merge-on-Read 均可
Standard data lake 表✅ 支持任何格式 (Parquet, Avro, CSV 等)
Spectrum 外表 JOIN Redshift 本地表✅ 支持-
Hudi / Delta Lake 表❌ 不支持只能全量创建

MV 刷新的增量支持(基于 Iceberg 表)

基表操作增量刷新备注
INSERT(追加数据)✅ 支持最高效的场景
DELETE(删除数据)✅ 支持-
UPDATE(更新数据)✅ 支持-
Table Compaction(表压缩)✅ 支持-
Snapshot 过期 + 带聚合的 MV⚠️ 退化为全量刷新需确保 snapshot 未被清理

SQL 构造的增量刷新支持

SQL 构造增量刷新
SELECT, FROM, INNER JOIN, WHERE, GROUP BY, HAVING✅ 支持
聚合:SUM, MIN, MAX, AVG, COUNT✅ 支持
OUTER JOIN (LEFT/RIGHT/FULL)❌ 不支持
UNION / INTERSECT / EXCEPT❌ 不支持
DISTINCT 聚合 (COUNT DISTINCT 等)❌ 不支持
MEDIAN, PERCENTILE_CONT, LISTAGG❌ 不支持

前置条件与权限配置

环境要求

IAM 最小权限策略

-- Redshift 需要的 IAM 权限(用于访问 Glue Catalog + S3 数据)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "GlueCatalogAccess",
      "Effect": "Allow",
      "Action": [
        "glue:GetDatabase",
        "glue:GetDatabases",
        "glue:GetTable",
        "glue:GetTables",
        "glue:GetPartition",
        "glue:GetPartitions",
        "glue:BatchGetPartition"
      ],
      "Resource": [
        "arn:aws:glue:<REGION>:<ACCOUNT_ID>:catalog",
        "arn:aws:glue:<REGION>:<ACCOUNT_ID>:database/*",
        "arn:aws:glue:<REGION>:<ACCOUNT_ID>:table/*/*"
      ]
    },
    {
      "Sid": "S3DataAccess",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket",
        "s3:GetBucketLocation"
      ],
      "Resource": [
        "arn:aws:s3:::<YOUR_BUCKET>",
        "arn:aws:s3:::<YOUR_BUCKET>/*"
      ]
    }
  ]
}

设置默认 IAM Role

-- 在 Redshift 中设置默认 IAM Role
ALTER CLUSTER SET DEFAULT IAM_ROLE 'arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>';

完整动手实践(Step-by-Step)

步骤一:在 Athena / EMR 中创建 Iceberg 表并写入数据

-- 在 Athena 中操作
CREATE DATABASE iceberg_demo;

CREATE TABLE iceberg_demo.sales (
  sale_id     BIGINT,
  sale_date   DATE,
  region      STRING,
  product     STRING,
  quantity    INT,
  amount      DECIMAL(12,2)
)
PARTITIONED BY (region, bucket(16, sale_id))
LOCATION 's3://your-bucket/iceberg/sales/'
TBLPROPERTIES (
  'table_type' = 'iceberg',
  'write_compression' = 'snappy',
  'format' = 'parquet'
);

-- 插入初始数据
INSERT INTO iceberg_demo.sales VALUES
(1, DATE '2024-01-15', 'APAC', 'Laptop',    10, 9500.00),
(2, DATE '2024-01-15', 'APAC', 'Monitor',    5, 2500.00),
(3, DATE '2024-01-16', 'EMEA', 'Laptop',    15, 14250.00),
(4, DATE '2024-02-01', 'AMER', 'Keyboard',  30, 1800.00),
(5, DATE '2024-02-01', 'AMER', 'Mouse',     50, 1250.00);

步骤二:在 Redshift 中创建外部 Schema

-- 在 Redshift Query Editor v2 中执行
CREATE EXTERNAL SCHEMA iceberg_schema
FROM DATA CATALOG
DATABASE 'iceberg_demo'
REGION 'us-east-1'
IAM_ROLE DEFAULT;

步骤三:验证外部表可查询

SELECT * FROM iceberg_schema.sales LIMIT 10;

步骤四:创建物化视图

-- 创建带聚合的物化视图
CREATE MATERIALIZED VIEW mv_sales_summary
AS
SELECT
    region,
    product,
    COUNT(*) AS order_count,
    SUM(quantity) AS total_qty,
    SUM(amount) AS total_amount,
    AVG(amount) AS avg_amount
FROM iceberg_schema.sales
GROUP BY region, product;

步骤五:在基表中插入新数据(模拟增量)

-- 回到 Athena 插入增量数据
INSERT INTO iceberg_demo.sales VALUES
(6, DATE '2024-02-15', 'APAC', 'Laptop',     8, 7600.00),
(7, DATE '2024-02-15', 'EMEA', 'Monitor',   12, 6000.00);

步骤六:增量刷新物化视图

-- 在 Redshift 中执行增量刷新
REFRESH MATERIALIZED VIEW mv_sales_summary;

步骤七:验证增量刷新状态

-- 查看刷新历史
SELECT
    mv_name,
    status,
    refresh_type,   -- 'Incremental' 表示增量刷新成功
    start_time,
    end_time,
    rows_inserted,
    rows_deleted
FROM SYS_MV_REFRESH_HISTORY
WHERE mv_name = 'mv_sales_summary'
ORDER BY start_time DESC
LIMIT 5;

步骤八:测试 DELETE / UPDATE 后的增量刷新

-- 在 Athena 中执行 DELETE
DELETE FROM iceberg_demo.sales WHERE sale_id = 4;

-- 在 Athena 中执行 UPDATE
UPDATE iceberg_demo.sales
SET amount = 10000.00
WHERE sale_id = 1;

-- 回到 Redshift 刷新
REFRESH MATERIALIZED VIEW mv_sales_summary;

-- 验证数据已更新
SELECT * FROM mv_sales_summary ORDER BY region, product;

自动刷新 (Auto Refresh) 配置

创建时启用自动刷新

CREATE MATERIALIZED VIEW mv_sales_summary
AUTO REFRESH YES
AS
SELECT
    region,
    product,
    SUM(amount) AS total_amount
FROM iceberg_schema.sales
GROUP BY region, product;

对已有 MV 开启自动刷新

ALTER MATERIALIZED VIEW mv_sales_summary AUTO REFRESH YES;

自动刷新行为说明

自动刷新机制
  • Redshift 在检测到基表变化后会尽快触发刷新,但不是实时的
  • 系统会综合考虑:当前集群负载、刷新所需资源、MV 使用频率
  • 用户工作负载优先级高于自动刷新——高负载时可能延迟刷新
  • 自 2026 年 2 月起(Patch 198+),Auto REFRESH 以用户查询优先级执行(仅限 Provisioned)
  • Iceberg 外表上的 MV 支持 Auto Refresh(但不支持与 datasharing 表组合使用)
注意

如果物化视图定义中包含外部 schema引用,则 AUTO REFRESH YES 不支持与 Automated MV (AutoMV)自动查询重写 (Auto Query Rewrite) 结合使用。即:

  • Iceberg 外表上的 MV 不支持自动查询重写 (AQMV)
  • 需要用户显式查询 MV 名称来获取加速效果

确定性刷新(替代方案)

如果需要严格的刷新周期,可使用 Redshift Scheduler API 或 Amazon EventBridge 定时触发:

-- 使用 Redshift Data API + EventBridge 实现定时刷新
-- EventBridge Rule: 每小时执行一次
-- Target: Redshift Data API → ExecuteStatement

-- SQL Statement:
REFRESH MATERIALIZED VIEW mv_sales_summary;

与 Amazon S3 Tables 结合使用

Amazon S3 Tables 提供完全托管的 Iceberg 表体验,自带自动 compaction 和 snapshot 管理。结合 Redshift MV 使用时,架构如下:

配置步骤

1

创建 S3 Table Bucket 并集成 Glue Catalog

在 S3 控制台创建 Table Bucket,勾选 "Enable Integration" 以自动集成 Glue Data Catalog

2

创建 Glue Database Resource Link

在 Glue Console 中创建一个 Resource Link Database 指向 S3 Tables Catalog

3

在 Redshift 中创建外部 Schema

通过 Resource Link 访问 S3 Tables 中的 Iceberg 表

4

创建物化视图 & 增量刷新

与普通 Iceberg 表操作完全一致

-- Redshift 中创建指向 S3 Tables 的外部 Schema
CREATE EXTERNAL SCHEMA salesdb
FROM DATA CATALOG DATABASE 'salesdb'
IAM_ROLE 'arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>'
REGION '<REGION>'
CATALOG_ID '<ACCOUNT_ID>';

-- 物化视图可存储在 S3 Tables 中或普通 S3 Bucket 中
-- 取决于你的访问模式和成本考量
S3 Tables 的优势
  • 自动 Compaction:S3 Tables 自动合并小文件,减少 Redshift MV 刷新时遇到 delete files 过多的问题
  • 自动 Snapshot 管理:无需手动清理过期 snapshot
  • 可调频率:通过 put-table-maintenance-configuration 调高 compaction 频率

性能基准与优化建议

官方 TPC-DS 基准测试结果

测试条件:3TB TPC-DS,Iceberg Copy-on-Write,ra3.4xl × 4 节点,34 个 MV,1% 数据变更

场景平均加速比最大加速比最小加速比
INSERT 后增量刷新 vs 全量刷新13.5×43.8×1.8×
DELETE 后增量刷新 vs 全量刷新15×47×1.2×

优化建议

  1. 优先使用 Copy-on-Write 模式:CoW 模式下增量刷新效率更高,避免 delete files 累积
  2. 定期 Compaction:如果使用 Merge-on-Read (如 Flink upsert 写入),定期执行 rewrite_data_files 避免 delete files 过多
  3. 控制 Snapshot 保留:确保 Redshift 上次刷新对应的 snapshot 未被过期清理,否则退化为全量刷新
  4. 选择合适的 MV 粒度:MV 聚合粒度越粗,增量刷新的效率优势越大
  5. 利用分布键 (DISTKEY) 和排序键 (SORTKEY):为 MV 指定与查询模式匹配的分布和排序
  6. 监控单文件删除位置数:Iceberg 表单个 data file 中被删除位置不能超过 400 万个
-- 为 MV 指定分布和排序策略
CREATE MATERIALIZED VIEW mv_sales_optimized
DISTSTYLE KEY
DISTKEY(region)
SORTKEY(sale_date)
AUTO REFRESH YES
AS
SELECT
    region,
    sale_date,
    SUM(amount) AS total_amount,
    COUNT(*) AS order_count
FROM iceberg_schema.sales
GROUP BY region, sale_date;

监控与运维

关键系统视图

系统视图用途
SYS_MV_REFRESH_HISTORY查看 MV 刷新历史:时间、状态、刷新类型(增量/全量)、行数变化
SVL_MV_REFRESH_STATUS旧版刷新状态视图(推荐用 SYS_MV_REFRESH_HISTORY)
STV_MV_INFO查看 MV 当前状态:是否 stale、刷新类型、auto refresh 状态
STL_EXPLAIN查看查询执行计划,确认是否命中 MV

常用监控查询

-- 查看所有 MV 的刷新历史和类型
SELECT
    mv_name,
    status,
    refresh_type,
    start_time,
    end_time,
    DATEDIFF(second, start_time, end_time) AS duration_sec,
    rows_inserted,
    rows_deleted
FROM SYS_MV_REFRESH_HISTORY
ORDER BY start_time DESC
LIMIT 20;

-- 查看 MV 当前状态(是否过期、刷新类型)
SELECT
    name,
    state,           -- 1=up-to-date, 0=stale
    autorewrite,     -- 是否支持自动重写
    autorefresh      -- 是否启用自动刷新
FROM STV_MV_INFO;

-- 确认查询是否被重写为使用 MV
EXPLAIN
SELECT region, SUM(amount)
FROM iceberg_schema.sales
GROUP BY region;
-- 如果看到 "Seq Scan on mv_tbl__..." 则表示查询已被重写

告警建议

限制与注意事项

重要限制

增量刷新会退化为全量刷新的场景

功能限制

MaxMessageSize 问题(delete files 过多)

已知问题:Error Code 1009

当 Iceberg 表(特别是 Flink CDC/upsert 模式写入的表)积累过多 delete files 时,Redshift Spectrum 查询计划消息体积可能超限,导致 non-PADB exception code 1009 (MaxMessageSize) 错误。

解决方案优先级:

  1. 使用 S3 Tables 自动 compaction(调高频率)
  2. Flink 改用 Copy-on-Write 模式
  3. 定期手动 rewrite_data_files(delete-file-threshold=10,每 15-30 分钟)
  4. 创建 Incremental MV(MV 本身可缓解该问题)
  5. 迁移到 RA3 RG 节点或 Redshift Serverless(本地执行不走 Spectrum 消息总线)

最佳实践总结

#最佳实践原因
1优先使用 Copy-on-Write 模式的 Iceberg 表增量刷新效率最高,避免 delete files 累积
2MV 聚合使用 SUM/COUNT/AVG/MIN/MAX这些聚合函数支持增量刷新
3避免 OUTER JOIN 和 DISTINCT 聚合会导致只能全量刷新
4设置合理的 Snapshot 保留策略防止增量刷新退化为全量
5对高频更新表启用 S3 Tables 自动 Compaction自动清理 delete files,保持增量刷新健康
6为 MV 指定 DISTKEY 和 SORTKEY优化后续查询性能
7使用 SYS_MV_REFRESH_HISTORY 监控刷新及时发现退化为全量刷新的问题
8业务 BI 查询直接引用 MV 名称Iceberg 外表 MV 不支持自动查询重写
9需要确定性刷新时使用 Scheduler / EventBridgeAuto Refresh 是"尽力而为",不保证时间
10测试 CASCADE 关键字用于嵌套 MV 刷新确保依赖链中所有 MV 都被刷新

参考文档