Doris 实战与架构

分析型数据库 / 源码阅读 / LESSON 19

物化视图与查询加速——从 Rollup 到透明改写

从同步 Rollup、异步物化视图、透明改写、刷新策略和资源隔离理解查询加速设计。

阅读时间
55 分钟
学习路径
Doris 实战与架构
内容来源
Doris 深度笔记

预计阅读时间: 55 分钟 前置阅读: doc-03, doc-08, doc-18 下一次阅读: doc-20(实时写入、更新与删除)


1. 加速手段不是只有索引

Doris 查询加速可以分成五层:

表设计: Partition / Bucket / Sort Key
  → 存储索引: Prefix / ZoneMap / Bloom / Bitmap / Inverted
    → 物化视图: 同步 Rollup / 异步 MV / 透明改写
      → 缓存: SQL Cache / Condition Cache / Data Cache
        → 执行调优: RuntimeFilter / Join / TopN / Spill / Workload Group

物化视图解决的问题是: 把高成本计算提前做掉, 让查询读更少的数据或更接近目标形态的数据。

参考:


2. 同步物化视图: 表内 Rollup 思路

同步物化视图更接近传统 Rollup。它跟随基表写入同步维护, 适合单表聚合和排序前缀优化。

示例:

CREATE MATERIALIZED VIEW mv_event_service_daily AS
SELECT
    date_trunc(event_time, 'day') AS dt,
    tenant_id,
    service_name,
    count(*) AS cnt
FROM event_log
GROUP BY
    date_trunc(event_time, 'day'),
    tenant_id,
    service_name;

适合:

  • 单表聚合。
  • 高频 dashboard 查询。
  • 聚合维度稳定。
  • 可接受写入时维护成本。

不适合:

  • 多表 Join 很复杂。
  • 刷新窗口需要独立控制。
  • 基表更新频繁且视图维护成本过高。

3. 异步物化视图: 更像可管理的数据产品

异步物化视图可以独立刷新, 支持更复杂 SQL 和分区增量刷新。它更适合专家级场景:

  • 多表 Join 预计算。
  • 明细到宽表或汇总表。
  • 湖仓外表加速。
  • 多层指标模型。
  • 生产报表稳定加速。

示例:

CREATE MATERIALIZED VIEW mv_order_user_daily
BUILD IMMEDIATE
REFRESH AUTO ON MANUAL
PARTITION BY(dt)
DISTRIBUTED BY HASH(tenant_id) BUCKETS 24
AS
SELECT
    o.dt,
    o.tenant_id,
    u.city,
    count(*) AS order_cnt,
    sum(o.amount) AS amount
FROM fact_order o
JOIN dim_user u ON o.user_id = u.user_id
GROUP BY o.dt, o.tenant_id, u.city;

设计重点:

维度判断
刷新模式全量、分区增量、手动还是定时
分区对齐MV 分区能否映射基表分区
查询改写目标 SQL 是否符合可改写形态
资源隔离刷新是否放进独立 Workload Group
可用性刷新失败时是否允许读旧数据

4. 透明改写怎么理解

透明改写是指用户仍然查原 SQL, 优化器自动改写到物化视图。

用户 SQL
  → Nereids 解析逻辑计划
    → 匹配可用 MV
      → 判断字段、谓词、聚合、分区有效性
        → 选择成本更低的 MV 计划

判断一个 SQL 能不能被改写, 看四件事:

  1. MV 是否包含查询所需列。
  2. MV 的过滤范围是否覆盖查询范围。
  3. 聚合粒度是否能 roll-up 到查询粒度。
  4. Join 关系是否能表达同样语义。

反例:

-- MV 只有 dt, tenant_id 粒度
-- 查询要求 trace_id 明细, 不能从 MV 还原
SELECT trace_id
FROM event_log
WHERE dt = '2026-07-27';

5. 刷新策略

全量刷新

适合:

  • 数据量小。
  • 逻辑简单。
  • 作为早期验证。

风险:

  • 数据增长后刷新时间线性变长。
  • 刷新资源与在线查询竞争。

分区增量刷新

适合:

  • 时间分区事实表。
  • 每天或每小时新增数据。
  • 基表分区与 MV 分区能映射。

关键:

  • 分区列表达式要稳定。
  • 迟到数据要有补刷策略。
  • 历史分区修正要可手工触发。

嵌套物化视图

适合复杂指标分层:

明细表
  → 日级服务指标 MV
    → 租户级周报 MV
      → 产品看板查询

风险:

  • 依赖链变长。
  • 上游刷新失败影响下游。
  • 需要明确血缘和告警。

6. MV 与 Workload Group

物化视图刷新本质上也是查询和写入任务。生产环境必须把刷新资源管起来。

-- 思路示例: 为 MV 刷新准备独立资源组
CREATE WORKLOAD GROUP mv_refresh
PROPERTIES (
    "cpu_share" = "512",
    "memory_limit" = "30%"
);

然后在物化视图属性或调度层把刷新任务放到指定资源组。资源太小会导致刷新失败, 太大会挤压在线查询。专家要按刷新窗口、数据量和 SLA 做压测。


7. 与其他加速能力组合

目标首选补充
重复 dashboard 查询SQL CacheMV 稳定预聚合
高选择性等值过滤Sort Key / BloomInverted Index
文本检索Inverted Index结果 MV
大表 JoinColocate / Broadcast异步 MV
湖仓热数据Data Cache外表 MV
TopNTopN 优化排序键和小 LIMIT

不要用 MV 掩盖所有问题:

  • 如果基表分区错误, MV 只是在复制问题。
  • 如果查询模式很分散, MV 维护成本可能高于收益。
  • 如果数据实时性要求极高, 刷新延迟需要写进 SLA。

8. 验证 MV 是否真的有效

验证步骤:

EXPLAIN SELECT ...;

看计划是否命中物化视图。然后开启 Profile 对比:

SET enable_profile = true;
SELECT ...;
SHOW PROFILELIST;
SHOW PROFILE WHERE query_id = '...';

对比指标:

指标期望
扫描行数明显下降
Scan 时间明显下降
Join/聚合时间被提前计算或降低
总耗时稳定下降
刷新耗时在窗口内
刷新资源不影响在线查询

9. 专家级 MV 设计模板

1. 目标 SQL: 哪些 SQL 或报表要加速
2. 基表模型: 分区、分桶、排序键、数据量
3. 查询共性: 过滤列、Join、Group By、时间窗口
4. MV 定义: 列、粒度、分区、分桶
5. 刷新策略: 全量/增量/手动/定时
6. 资源隔离: Workload Group 与刷新窗口
7. 正确性: 迟到数据、历史修正、失败重试
8. 观测: 刷新耗时、失败率、命中率
9. 回滚: 删除 MV 后原 SQL 是否可接受

一句话总结:

Doris 的物化视图不是"多建一张快表", 而是把查询成本、刷新成本、数据一致性和资源隔离放到同一个设计里权衡。