跳到主要内容

物化视图

问题

什么是物化视图?如何用物化视图加速 OLAP 查询?

答案

普通视图 vs 物化视图

维度普通视图(View)物化视图(Materialized View)
存储不存储数据,只存 SQL存储计算结果
查询速度每次重新计算直接读取预计算结果
数据新鲜度实时取决于刷新策略
适用场景SQL 复用查询加速

典型场景

-- 原始明细表(10 亿行)
CREATE TABLE events (
event_date Date,
user_id UInt64,
channel String,
event_name String,
amount Decimal(18,2)
) ENGINE = MergeTree()
ORDER BY (event_date, user_id);

-- 高频查询:每天按频道统计 PV/UV/金额
-- 每次查询需扫描全量数据,耗时 30s+
SELECT
event_date,
channel,
COUNT(*) AS pv,
COUNT(DISTINCT user_id) AS uv,
SUM(amount) AS total_amount
FROM events
GROUP BY event_date, channel;

各引擎物化视图实现

-- ClickHouse 物化视图:数据写入时自动聚合
CREATE MATERIALIZED VIEW events_daily_mv
ENGINE = SummingMergeTree()
ORDER BY (event_date, channel)
AS SELECT
event_date,
channel,
count() AS pv,
uniqState(user_id) AS uv_state, -- 存储中间状态
sum(amount) AS total_amount
FROM events
GROUP BY event_date, channel;

-- 查询物化视图(毫秒级)
SELECT
event_date,
channel,
pv,
uniqMerge(uv_state) AS uv, -- 合并中间状态
total_amount
FROM events_daily_mv
WHERE event_date = '2024-01-01';
ClickHouse 物化视图特点
  • 增量更新:只对新写入的数据触发计算
  • 已有数据不回填:创建 MV 前的数据需手动 INSERT INTO ... SELECT ...
  • uniqState / uniqMerge:近似去重的中间状态存储

刷新策略

策略说明适用场景
实时增量数据写入时触发ClickHouse MV
定时全量周期性全量重建PostgreSQL REFRESH
异步增量后台异步刷新StarRocks Async MV
手动触发按需刷新一次性分析

物化视图设计原则

设计建议
  1. 只为高频查询创建:物化视图有存储和维护成本
  2. 聚合粒度适中:太细效果差,太粗不灵活
  3. 优先选择固定维度日期 + 频道日期 + 地区
  4. 监控命中率:定期检查物化视图是否被实际使用
  5. 控制数量:过多物化视图会影响写入性能

常见面试问题

Q1: 物化视图和预计算(提前聚合宽表)有什么区别?

答案

维度物化视图预计算宽表
创建方式DDL 声明式ETL 脚本
维护引擎自动管理手动维护调度
查询改写自动(Doris)需修改查询
灵活性受引擎限制完全自定义
适合场景固定聚合模式复杂多表 JOIN

Q2: 物化视图的缺点是什么?

答案

  • 存储成本:额外存储预计算结果
  • 写入性能下降:数据写入时需同步更新 MV
  • 数据延迟:异步刷新存在延迟
  • 维护成本:源表 Schema 变更需同步更新 MV

相关链接