增量刷新 (Incremental Refresh) 技术深度指南 — 架构原理、完整实践、性能优化与注意事项
物化视图 (Materialized View, MV) 是 Amazon Redshift 的一项核心优化能力——它将复杂查询的结果预计算并持久化存储在 Redshift 本地,后续查询直接读取预计算结果,跳过昂贵的扫描和聚合。
自 2024 年 10 月 GA 起,Amazon Redshift 支持在 Apache Iceberg 外部表上创建物化视图,并支持增量刷新 (Incremental Refresh)——Redshift 能够利用 Iceberg 的 snapshot 机制,只读取自上次刷新后发生变化的数据,而非全表扫描,大幅降低刷新成本和时间。
* 基准: AWS 官方 TPC-DS 3TB 测试,Iceberg CoW 模式,ra3.4xl × 4 节点,34 个物化视图,1% 数据变更
创建 MV、执行增量/全量刷新、存储预计算结果、响应分析查询
维护 Iceberg 表元数据、snapshot 列表、manifest 文件位置
存储 Iceberg 数据文件 (Parquet)、metadata.json、manifest list
Iceberg 的 snapshot-based 事务管理是增量刷新的关键。当 Redshift 刷新 MV 时:
Iceberg 的两种写模式都被支持:
两种模式均支持增量刷新,但 CoW 模式的增量刷新效率通常更高。
| 基表类型 | 增量创建 | 备注 |
|---|---|---|
| Iceberg 表(分区/非分区) | ✅ 支持 | Copy-on-Write & Merge-on-Read 均可 |
| Standard data lake 表 | ✅ 支持 | 任何格式 (Parquet, Avro, CSV 等) |
| Spectrum 外表 JOIN Redshift 本地表 | ✅ 支持 | - |
| Hudi / Delta Lake 表 | ❌ 不支持 | 只能全量创建 |
| 基表操作 | 增量刷新 | 备注 |
|---|---|---|
| INSERT(追加数据) | ✅ 支持 | 最高效的场景 |
| DELETE(删除数据) | ✅ 支持 | - |
| UPDATE(更新数据) | ✅ 支持 | - |
| Table Compaction(表压缩) | ✅ 支持 | - |
| Snapshot 过期 + 带聚合的 MV | ⚠️ 退化为全量刷新 | 需确保 snapshot 未被清理 |
| 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 | ❌ 不支持 |
-- 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>/*"
]
}
]
}
-- 在 Redshift 中设置默认 IAM Role ALTER CLUSTER SET DEFAULT IAM_ROLE 'arn:aws:iam::<ACCOUNT_ID>:role/<ROLE_NAME>';
-- 在 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 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;
-- 在 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;
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;
ALTER MATERIALIZED VIEW mv_sales_summary AUTO REFRESH YES;
如果物化视图定义中包含外部 schema引用,则 AUTO REFRESH YES 不支持与 Automated MV (AutoMV) 和 自动查询重写 (Auto Query Rewrite) 结合使用。即:
如果需要严格的刷新周期,可使用 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 提供完全托管的 Iceberg 表体验,自带自动 compaction 和 snapshot 管理。结合 Redshift MV 使用时,架构如下:
在 S3 控制台创建 Table Bucket,勾选 "Enable Integration" 以自动集成 Glue Data Catalog
在 Glue Console 中创建一个 Resource Link Database 指向 S3 Tables Catalog
通过 Resource Link 访问 S3 Tables 中的 Iceberg 表
与普通 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 中 -- 取决于你的访问模式和成本考量
put-table-maintenance-configuration 调高 compaction 频率测试条件: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× |
rewrite_data_files 避免 delete files 过多-- 为 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__..." 则表示查询已被重写
SYS_MV_REFRESH_HISTORY 中 status = 'Failed' 的记录当 Iceberg 表(特别是 Flink CDC/upsert 模式写入的表)积累过多 delete files 时,Redshift Spectrum 查询计划消息体积可能超限,导致 non-PADB exception code 1009 (MaxMessageSize) 错误。
解决方案优先级:
rewrite_data_files(delete-file-threshold=10,每 15-30 分钟)| # | 最佳实践 | 原因 |
|---|---|---|
| 1 | 优先使用 Copy-on-Write 模式的 Iceberg 表 | 增量刷新效率最高,避免 delete files 累积 |
| 2 | MV 聚合使用 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 / EventBridge | Auto Refresh 是"尽力而为",不保证时间 |
| 10 | 测试 CASCADE 关键字用于嵌套 MV 刷新 | 确保依赖链中所有 MV 都被刷新 |