一、引言
StarRocks 进入实时数仓场景后,很多团队都会遇到同一个问题:到底是建大宽表、建主题域模型、建指标层,还是继续沿用传统数仓分层?答案不是四选一,而是把它们放在不同层次里各司其职。

二、StarRocks 改变了什么
传统离线数仓通常把大量建模工作放在 Spark、Hive、Flink 或调度系统中完成,OLAP 引擎更多承担查询服务。StarRocks 的不同之处在于,它本身就具备列式存储、分区分桶、表模型、物化视图、视图、索引和查询改写等能力,可以把一部分建模、预聚合和加速工作内收进 OLAP 层。StarRocks 可以通过视图与异步物化视图结合完成分层建模,物化视图可用于简化 ETL Pipeline、改善数据质量和查询性能。
实时数仓不再只有"Flink 产出结果表,StarRocks 查询结果表"这一种形态。对于实时性要求很高、逻辑较轻的链路,可以用视图表达语义;对于高频查询、复杂 Join、聚合和窗口计算,可以用异步物化视图承载预计算;对于应用强绑定的查询,可以在 ADS 层建设宽表或物化结果。
三、表模型怎么选
StarRocks 的建模首先是表模型选择,明细表适合原始数据和不需要约束、预聚合的日志数据;主键表具备唯一非空约束,适合实时更新、部分列更新和实时查询;聚合表适合保存预聚合数据;更新表已逐渐被主键表取代。
| 场景 | 推荐表模型 | 原因 |
|---|---|---|
| 原始日志、埋点、行为流水 | 明细表 | 保留重复行和原始事实,不做唯一约束 |
| Kafka 事件明细,不需要更新 | 明细表 | 追加写入为主,适合 ODS 或 DWD 明细 |
| MySQL CDC 订单、用户、商品 | 主键表 | 支持主键替换、更新、删除和部分列更新 |
| 用户画像大宽表 | 主键表 | 按用户主键持续更新标签列 |
| 公共粒度汇总 | 聚合表或异步物化视图 | 降低查询时聚合成本 |
| 高频多表 Join 查询 | 异步物化视图 | 支持多表构建、刷新和查询改写 |
| 单表固定聚合加速 | 同步物化视图 | 本质是基表索引,适合单表聚合加速 |
一个常见误区是把 StarRocks 的DUPLICATE KEY理解成"去重键",明细表的DUPLICATE KEY不具备唯一约束,如果新数据的 Duplicate Key 与旧数据相同,新旧数据都会保留;明细表还支持用ORDER BY指定排序键,且同时使用ORDER BY和DUPLICATE KEY时,DUPLICATE KEY不生效。

四、宽表不是万能药
宽表在实时 OLAP 中很有吸引力,因为它把事实和维度提前 Join 好,查询侧只需要过滤、分组和聚合,能显著降低查询复杂度。对于实时大屏、客服看板、用户画像、订单分析这种查询模式相对稳定的场景,宽表是合理的。
但宽表的问题也很明显:列膨胀、口径耦合、维度变更成本高、多个主题混杂、重复存储严重。StarRocks 支持 ARRAY、JSON、MAP、STRUCT 等复杂半结构化类型,也支持列式存储和索引,这能缓解宽表在存储和查询上的部分压力,但不能替代良好的业务建模。
宽表应该出现在 ADS 或特定 DWS 层,而不是吞掉整个数仓:
sql
错误姿势:
ODS --> 一张超级宽表 --> 所有报表
|
+-- 订单字段
+-- 用户字段
+-- 商品字段
+-- 营销字段
+-- 履约字段
+-- 售后字段
+-- 风控字段
问题:
1. 主题边界消失
2. 指标口径散落在 SQL 中
3. 维度变更牵一发动全身
4. 新业务接入只能继续加列
更合理的姿势是:
yaml
ODS 明细
|
v
DWD 业务事实 + DIM 维度
|
+--------------------+
| |
v v
DWS 主题汇总 ADS 场景宽表
| |
v v
公共指标复用 高性能应用查询
也就是说,宽表是一种服务查询的物理模型,不是业务建模的全部。业务模型要稳定,宽表可以灵活;如果业务模型本身就是一张宽表,后续维护成本会快速失控。
五、主题域先于指标层
主题域的价值是划清业务边界。订单、交易、履约、营销、用户、商品、库存、风控,这些主题域对应不同业务过程,也对应不同事实表和维度表。如果主题域没有划清,指标层会变成一堆看似标准、实际互相污染的 SQL 片段。
一个推荐的主题建模方式是先找业务过程,再找事实粒度:
lua
主题域:交易
|
+-- 业务过程:下单
| 粒度:一行一个订单
| 事实表:dwd_trade_order_df / dwd_trade_order_rt
|
+-- 业务过程:支付
| 粒度:一行一次支付
| 事实表:dwd_trade_payment_df / dwd_trade_payment_rt
|
+-- 业务过程:退款
| 粒度:一行一次退款
| 事实表:dwd_trade_refund_df / dwd_trade_refund_rt
|
+-- 公共维度:用户、商品、店铺、渠道、地区
主题域建模落到 StarRocks 中,可以采用星型模型作为 DWD/DWS 的基础结构:
lua
+----------------+
| dim_user |
+-------+--------+
|
|
+------------+ +-----v------+ +-------------+
| dim_shop +-----> fact_order <-----+ dim_product |
+------------+ +-----+------+ +-------------+
|
|
+-------v--------+
| dim_channel |
+----------------+
StarRocks 的异步物化视图支持多表 Join,并可基于事实表分区刷新。一个物化视图仅能与一个基表做分区关联,通常选择事实表的分区键;事实表分区变化后,物化视图对应分区刷新,而其他未关联表变化时默认可能刷新整个物化视图。这意味着,在 StarRocks 中做星型建模时,事实表分区设计非常关键,维度表更新策略也必须被提前设计。
六、指标层怎么落地
指标层不是简单建几张聚合表,而是把"指标口径"从应用 SQL 中抽出来。对于实时数仓,指标层至少要区分三类指标:
| 指标类型 | 示例 | 建模方式 |
|---|---|---|
| 原子指标 | 支付金额、订单数、退款金额 | 从 DWD 事实表直接聚合 |
| 派生指标 | 今日支付金额、近 7 日支付用户数 | 原子指标 + 时间周期 + 过滤条件 |
| 复合指标 | 支付转化率、客单价、退款率 | 多个原子或派生指标组合 |
在 StarRocks 中,指标层有三种常见实现方式:
sql
方式一:视图
适合:口径表达、轻量封装、实时性优先
代价:每次查询仍需计算
方式二:聚合表
适合:固定粒度、固定聚合、写入时预聚合
代价:灵活性较弱,明细不可回溯到原始行
方式三:异步物化视图
适合:多表 Join、公共聚合、透明查询改写、近实时指标层
代价:需要管理刷新、分区、TTL 和一致性
StarRocks视图和物化视图有清晰边界:视图不存储数据,无存储开销,适合业务建模和数据治理;物化视图存储预计算结果,有额外存储成本,但可加速查询,适合数据建模、透明加速和湖仓一体。
一个指标层可以这样设计:
lua
DWD 明细事实
|
+-- dwd_trade_order_rt
+-- dwd_trade_payment_rt
+-- dwd_trade_refund_rt
|
v
DWS 指标层
|
+-- dws_trade_order_1m_mv
| 粒度:分钟 + 店铺 + 渠道
| 指标:订单数、下单金额
|
+-- dws_trade_payment_1m_mv
| 粒度:分钟 + 店铺 + 渠道
| 指标:支付订单数、支付金额、支付用户数
|
+-- dws_trade_refund_1d_mv
粒度:天 + 店铺 + 商品类目
指标:退款金额、退款订单数
示例 SQL 可以写成:
scss
CREATE MATERIALIZED VIEW dws_trade_payment_1m_mv
REFRESH ASYNC
PARTITION BY date_trunc('DAY', pay_time)
DISTRIBUTED BY HASH(shop_id, channel_id)
ORDER BY (pay_minute, shop_id, channel_id)
AS
SELECT
date_trunc('MINUTE', pay_time) AS pay_minute,
shop_id,
channel_id,
count(*) AS pay_order_cnt,
sum(pay_amount) AS pay_amount,
bitmap_union(to_bitmap(user_id)) AS pay_user_bitmap
FROM dwd_trade_payment_rt
GROUP BY
date_trunc('MINUTE', pay_time),
shop_id,
channel_id;
这里的重点不是 SQL 本身,而是分工:DWD 保存支付事实,DWS 保存公共粒度指标,ADS 再根据应用需要拼装或进一步物化。
七、小结
StarRocks 里的实时数仓不是"把离线数仓搬进 OLAP",也不是"把所有东西都做成大宽表"。主题域定义边界,维度建模定义语义,指标层定义口径,宽表优化查询,StarRocks 的表模型和物化视图负责把这些设计变成高性能、可维护的物理实现。
在 StarRocks 中建实时数仓,可以采用如下原则:
vbnet
原始事件要保留,业务事实要建模,复杂指标要物化,应用查询要隔离。
ODS:保留原始明细,优先明细表或主键表
DWD:清洗、拉齐业务语义,保留可追溯事实
DIM:小维表主键化,变更频繁时用主键表
DWS:围绕主题域沉淀公共汇总和可复用指标
ADS:面向应用构建宽表、物化视图或查询加速模型