实时 OLAP 引擎选型指南
一条贯穿“查询形态—更新模式—资源弹性”的选型主线,与可复现的工程决策路径
技术评述 · 架构对比 · 压测方法 · 场景决策矩阵
摘要
实时 OLAP 引擎的选型长期被“跑分叙事”主导:谁更快、谁更省、谁更火。但工程实践反复证明,脱离查询形态、数据更新模式与资源弹性约束的横向对比,几乎无法迁移到真实业务。本文不复述参数表,而是确立一条贯穿全文的分析主线——“查询形态 × 更新模式 × 资源弹性”三维选型框架,把 ClickHouse、Apache Doris、StarRocks 放回各自的架构原点重新审视。
全文依次拆解三者的存储组织、执行模型、实时写入链路与多表关联能力,给出可操作的 POC 压测步骤、容量估算公式、分场景决策矩阵与迁移路径,并讨论存算分离、湖仓一体、向量化执行等趋势对选型结论的长期影响。笔者认为,选型的本质不是选“最快的引擎”,而是选“与你的数据更新节奏和查询形态最匹配的复杂度预算”。
目录
一、选型困境:为什么“跑分对比”总是失效
打开任何一篇 OLAP 引擎对比文章,你大概率会看到一张 TPCH/SSB 跑分表,然后是三段“各有千秋”的结论。这类内容并非没有价值,但它有一个致命缺陷:跑分测的是引擎在“理想查询形态”下的峰值能力,而生产系统跑的是“你的查询形态”下的稳定能力。两者之间隔着的,是数据更新频率、并发模型、Schema 变更、运维人力与预算约束。
笔者在多个实时数仓项目中观察到一个反复出现的现象:团队按跑分选了“最快”的引擎,上线三个月后却被“高频小批量更新导致合并放大”“点查并发打满 CPU”“多表 JOIN 内存溢出”等问题拖垮。反过来,一些看起来“不够快”的引擎,因为写入模型与业务节奏天然契合,反而跑得更稳。这说明选型的评价函数本身需要重构。
本文评述:把 OLAP 选型类比为“选车”是常见但危险的隐喻。跑分像零百加速,而生产系统更像“日常通勤 + 偶尔长途 + 长期保养”。真正决定体验的是路况匹配度与维护成本,而非峰值马力。因此本文拒绝以单一跑分作为主线,转而构建多维约束下的匹配框架。
从学术与工业界的公开资料看,列式存储、向量化执行、MPP 调度这些基础能力在三款引擎中都已相当成熟,差异更多体现在架构取舍上:ClickHouse 选择了“单表极致的列式扫描 + 有限 JOIN”,Doris 选择了“MPP + 融合多存储模型”,StarRocks 选择了“CBO 优化器 + 物化视图 + 全面向量化”。这些取舍没有绝对优劣,只有场景匹配度。理解取舍,比记住跑分更重要。
二、三维选型主线:查询形态、更新模式、资源弹性
为了让后续所有章节有统一的坐标系,这里先确立本文的分析主线。笔者认为,任何实时 OLAP 选型问题,都可以拆解为三个正交维度的约束:
维度一:查询形态(Query Shape)
是“大宽表单表聚合”还是“星型模型多表 JOIN”?是“固定报表”还是“即席探索”?是“高并发点查”还是“低频大扫描”?查询形态决定了引擎的执行模型与索引设计能否发挥。
维度二:更新模式(Update Pattern)
是“只追加(append-only)”还是“需要按主键 Upsert/Delete”?更新是“批量导入”还是“高频小事务”?更新模式直接决定合并(compaction)压力与查询一致性代价。
维度三:资源弹性(Elasticity)
计算与存储是否要独立扩缩?是否存在明显的“白天查询高峰、夜间写入高峰”?是否要求多租户隔离?资源弹性决定了存算一体还是存算分离的架构选择。
这三个维度并非孤立:高频 Upsert 会放大合并压力,进而影响查询延迟;多表 JOIN 会推高内存需求,进而影响弹性伸缩的粒度。因此选型不是逐项打分求和,而是寻找“约束交集”内的可行解。本文后续每一章,都会回到这三个维度上做判断。
三、ClickHouse:为“宽表扫描”而生的列式引擎
3.1 架构原点:MergeTree 与稀疏索引
ClickHouse 的核心存储结构是 MergeTree 家族。数据按分区(partition)组织,分区内按排序键(ORDER BY)有序存储为多个 data part,后台线程持续将小 part 合并为大 part。每个 part 内部按列存储,并维护稀疏主键索引(默认每 8192 行一个 granule 的索引项)与跳数索引(skip index)。
这种设计的直接后果是:范围扫描极快,点查与随机更新相对吃力。因为稀疏索引只记录 granule 的边界,精确到行的定位需要扫描 granule 内部;而 MergeTree 的更新语义长期依赖 ALTER UPDATE / DELETE 的 mutation 机制,属于“异步重写 part”的重操作。本文评述:MergeTree 的本质是“以写放大换读放大最小化”,它假设数据以大批次追加、查询以列扫描为主。一旦业务假设被打破(高频小批量 Upsert),优势就会反转为负担。
3.2 执行模型与向量化
ClickHouse 的执行引擎以“列块(block)”为处理单位,配合 SIMD 向量化指令与多级并行(节点间、核间、指令间)。在单表聚合、宽表过滤这类“ embarrassingly parallel ”的查询上,其效率非常高。官方文档与多篇工程博客都指出,ClickHouse 在单表大扫描场景下的吞吐优势,很大程度上来自“极简的调度开销 + 激进的向量化”。
但代价是 JOIN 能力相对受限。历史上 ClickHouse 的 JOIN 以右表广播(broadcast)为主,大表 JOIN 大表容易内存溢出;后续版本引入了更丰富的 JOIN 算法与 spilling,但整体仍不如原生 MPP 引擎在多表场景下从容。笔者认为,这不是“缺陷”,而是“定位”——ClickHouse 假设你已经在建模阶段把多表打平成宽表。
3.3 适用与不适用
- 适合:日志/埋点/监控指标等 append-only 宽表;单表聚合报表;高吞吐批量导入;对 SQL 兼容性要求不极端的场景。
- 不适合:高频按主键 Upsert 的维表关联;复杂多表即席查询;强事务一致性要求;需要频繁 UPDATE 明细行的业务。
延伸阅读:ClickHouse 官方文档的 MergeTree 引擎说明(clickhouse.com/docs)与官方基准测试仓库(github.com/ClickHouse/ClickBench)是理解其能力边界的起点。
四、Apache Doris:MPP 融合型的折中之道
4.1 架构原点:FE/BE 分离与多存储模型
Doris 采用 FE(Frontend)与 BE(Backend)分离架构:FE 负责元数据、查询解析、规划与调度,BE 负责存储与执行。它原生支持多种数据模型——Duplicate(明细)、Aggregate(聚合)、Unique(主键唯一,支持 Merge-on-Write)——这让它在“追加”与“更新”之间提供了连续光谱,而非二选一。
本文评述:Doris 的工程哲学是“融合”——用一套系统覆盖报表、明细、主键更新等多种负载,牺牲一点单表极致性能,换取建模与运维的简化。对于团队规模有限、不希望维护多套引擎的组织,这种折中往往比“单点最快”更有价值。
4.2 执行模型与优化器
Doris 采用 MPP 执行框架,支持两阶段聚合、Runtime Filter、Colocate Join 等分布式 JOIN 优化。其优化器经历了从规则型(RBO)到代价型(CBO)的演进,在星型模型多表关联上的表现明显优于“宽表优先”的引擎。Runtime Filter 在多表 JOIN 中能显著减少右表扫描量,这是 MPP 引擎的经典手段。
需要客观指出的是,CBO 的效果高度依赖统计信息的准确性。若统计信息陈旧或倾斜严重,CBO 可能给出次优计划。因此生产环境必须建立统计信息收集与校验机制,这一点在后续 POC 章节会展开。
4.3 适用与不适用
- 适合:需要同时支持明细查询、聚合报表与主键更新的融合型数仓;星型/雪花模型多表关联;希望统一技术栈的中小团队。
- 需谨慎:极端单表大扫描的峰值吞吐;超高频小事务更新(Merge-on-Write 仍有合并成本);对 SQL 方言有强依赖的存量迁移。
延伸阅读:Apache Doris 官方文档(doris.apache.org/docs)与官方 Benchmark 页面(doris.apache.org/benchmark)。
五、StarRocks:CBO 与物化视图驱动的多表加速
5.1 架构原点:FE/BE + 全面向量化
StarRocks 同样采用 FE/BE 分离架构,但其执行层从设计之初就以“全面向量化”为目标,配合 Pipeline 执行引擎,把算子间的调度开销降到较低水平。其表模型包括明细、聚合、主键(Primary Key,支持部分列更新与条件更新)等,主键模型在实时更新场景中被广泛采用。
笔者认为,StarRocks 最值得关注的是优化器与物化视图的组合拳。它较早地把 CBO 作为核心能力建设,并支持异步物化视图的自动改写(query rewrite)。这意味着“多表 JOIN 慢”这个问题,可以通过“预计算 + 透明改写”在系统层解决,而不必强迫业务改 SQL。这是一种“用空间换时间、用系统复杂度换业务简单度”的取舍。
5.2 物化视图的工程价值与陷阱
物化视图(Materialized View)不是新概念,但 StarRocks 把它做成了“可透明改写”的默认能力,这改变了建模方式:业务可以继续写规范化的多表 SQL,系统在后台维护预聚合结果并自动匹配。本文评述:这把“建模负担”从业务侧转移到了平台侧,是分工的优化;但代价是物化视图的刷新策略、存储成本与一致性窗口需要被认真管理,否则会出现“改写命中率低、刷新延迟高、存储膨胀”的三重陷阱。
5.3 适用与不适用
- 适合:多表关联复杂、希望用物化视图加速的报表与即席分析;需要主键更新与部分列更新的实时宽表;对向量化性能敏感的场景。
- 需谨慎:物化视图数量过多导致刷新与存储压力;团队缺乏对 CBO 统计信息维护的经验;极简单表场景可能“杀鸡用牛刀”。
延伸阅读:StarRocks 官方文档(docs.starrocks.io)与官方 Benchmark(starrocks.io/benchmark)。
六、实时写入链路对比:从消息队列到可查
实时性是三款引擎共同的关键词,但“实时”的实现路径差异很大。下面按“消息队列 → 导入 → 可见”的链路拆解。
本文评述:三者的“秒级”含义并不相同。ClickHouse 的延迟更多取决于“批次大小与合并节奏”,批次越小、part 越多,后台合并越吃力;Doris 与 StarRocks 通过 Merge-on-Write / Primary Key 模型,把“更新”做成了写入路径的一等公民,小批量更新的工程体验更平滑。但要注意,任何引擎的“实时”都不是免费的——它用持续的合并与版本管理成本,换取了低延迟可见性。
笔者认为:评估实时写入时,不要只看“单条写入延迟”,而要看“在目标 QPS 下持续运行 24 小时后,查询 P99 是否劣化”。很多写入链路的隐患,是在合并积压数小时后才暴露的。这一点应写进 POC 的验收标准。
七、多表关联与数据更新:三种“一致性”的代价
多表关联能力是选型中最容易被低估的维度。很多团队在 POC 阶段只测单表,上线后才发现 80% 的查询是星型 JOIN。三款引擎在这一维度的差异,本质是“一致性实现方式”的差异。
7.1 ClickHouse:宽表优先,JOIN 为辅
ClickHouse 的 JOIN 在历史上以“右表广播”为主,适合“大表 JOIN 小维表”。大表 JOIN 大表需要依赖新版本的 spilling 与更优算法,但仍需谨慎设计。笔者认为,使用 ClickHouse 的正确姿势是“在建模阶段完成打平”,把 JOIN 成本前移到 ETL,而不是指望引擎在查询期解决。
7.2 Doris:MPP + Colocate Join
Doris 的 MPP 框架天然支持分布式 JOIN,Colocate Join 可以让同分布键的表在本地完成关联,避免数据 shuffle。Runtime Filter 能在运行时动态裁剪右表。这些能力让 Doris 在星型模型上表现稳健。但代价是:分布键设计不当会导致数据倾斜,Colocate 的前提(同分布列、同副本数)需要提前规划。
7.3 StarRocks:CBO + 物化视图改写
StarRocks 把“多表加速”做成了系统能力:CBO 负责选计划,物化视图负责把高频 JOIN 预计算。本文评述:这是一种“把 DBA 的经验固化成系统能力”的思路,降低了使用门槛;但它也把“物化视图治理”变成了新的运维课题——视图数量、刷新频率、存储成本之间需要持续调优。
八、POC 压测方法论:可复现的七步操作路径
选型不能靠“看文档 + 拍脑袋”。下面给出一套可复现的 POC 流程,强调“用你自己的数据和查询形态压测”。
- 采集真实查询:从生产慢查询日志中抽取 Top 50 查询,覆盖单表聚合、多表 JOIN、点查三类,按 QPS 加权。
- 构造数据集:用脱敏后的真实数据或按真实分布生成的模拟数据(须标注为模拟数据),规模至少为生产 1/10。
- 统一硬件:三套集群使用同规格机器、同网络、同副本数,避免“硬件差异”污染结论。
- 分阶段压测:先单查询延迟,再混合负载并发,最后叠加实时写入,观察 24 小时稳定性。
- 记录 P99 与资源:不仅看平均延迟,重点记录 P99、CPU、内存、磁盘 IO 与合并积压。
- 故障注入:模拟节点宕机、磁盘打满、写入突增,观察恢复时间与数据一致性。
- 成本折算:把资源消耗折算为月度账单,与性能一起纳入决策。
本文评述:POC 最常见的错误是“只测跑分查询”。跑分查询通常经过精心设计,无法代表生产的“脏查询”。笔者建议把“最丑的 10 条查询”单独列为一组,它们的表现往往更能区分引擎的鲁棒性。此外,压测报告应附带“复现脚本与配置”,否则结论不可审计。
延伸参考:ClickBench(benchmark.clickhouse.com)提供了公开的查询集与数据集,可作为构造压测用例的起点;但请务必用自有数据复测。
九、容量估算与成本模型:把账单算在前面
容量估算常被简化为“数据量 ÷ 单机容量”,这忽略了副本、索引、合并临时空间与增长冗余。下面给出一个可操作的估算框架(公式为工程经验模型,非某厂商官方数据):
原始日增量 D(GB/天,压缩前)
压缩比 R(列式存储典型 3~8,需实测)
副本数 N(通常 3)
索引与元数据开销系数 K(经验 1.1~1.3)
保留天数 T
合并临时空间系数 M(经验 1.2~1.5,更新越频繁越高)
所需裸容量 ≈ D × T × (1/R) × N × K × M
举例:日增 500GB、压缩比 5、3 副本、保留 90 天、K=1.2、M=1.3,则裸容量约 500×90×(1/5)×3×1.2×1.3 ≈ 42TB。本文评述:这个公式的价值不在于精确,而在于强迫团队把“副本、索引、合并”这些隐性成本显性化。很多预算超支,正是因为只算了“压缩后数据量”。
成本模型还应包含人力成本:ClickHouse 的运维需要理解 part 合并与 mutation;Doris/StarRocks 需要理解 FE 元数据与 CBO 统计信息。人力成本往往比机器成本更难量化,却更影响长期 TCO。
十、分场景决策矩阵与迁移路径
把前面的分析收敛成一张可操作的决策矩阵。注意:矩阵是“起点”而非“终点”,最终仍需 POC 验证。
迁移路径建议分三步:双写并行 → 灰度切读 → 下线旧链路。双写阶段要重点校验“聚合口径一致性”与“更新时序一致性”,这两类问题最容易在切流后暴露。本文评述:迁移的最大风险不是性能,而是“语义漂移”——同一个指标在新旧引擎上算出不同结果。因此必须建立对账机制,按天比对核心指标。
十一、前沿趋势:存算分离、湖仓一体与向量化
选型不是一次性决策,架构趋势会改变结论的“保质期”。以下三条趋势值得持续关注。
11.1 存算分离
三款引擎都在推进存算分离:计算节点无状态化,存储下沉到对象存储。这直接改变了“资源弹性”维度的权重——弹性从“加分项”变成“基础项”。本文评述:存算分离的代价是“远程 IO 延迟”,因此它更适合“计算密集但 IO 可缓存”的负载;对延迟极敏感的查询,仍需本地缓存或分层存储配合。
11.2 湖仓一体
对 Iceberg/Hudi/Paimon 等开放表格式的支持,正在成为 OLAP 引擎的标配。这意味着“数据湖里的原始数据”可以被直接查询,减少一份冗余存储。笔者认为,湖仓一体的真正价值不是“省存储”,而是“让 OLAP 引擎与数据湖共享同一份元数据与权限体系”,从而降低数据治理的碎片化。
11.3 向量化与硬件协同
向量化执行、SIMD、列式编码(字典、RLE、Delta)已是共同方向。进一步的差异可能来自“对新型硬件的利用”,例如对压缩数据直接计算、对 GPU/NPU 的探索。本文评述:硬件协同的收益高度依赖负载特征,短期内不宜作为选型主依据,但值得在技术雷达中持续跟踪。
十二、结语:选型是复杂度预算的分配问题
回到本文的主线:查询形态、更新模式、资源弹性。三款引擎没有绝对的赢家,只有“在你的约束下,复杂度预算分配得最合理”的那一个。ClickHouse 把复杂度放在“建模阶段”(打平宽表),换取查询期的极致;Doris 把复杂度放在“融合”(多模型共存),换取技术栈统一;StarRocks 把复杂度放在“优化器与物化视图治理”,换取多表查询的透明加速。
笔者认为,成熟的选型决策应当回答三个问题:我的查询形态是否与引擎的假设一致?我的更新模式是否会触发引擎的“重操作”?我的团队是否有能力维护这套复杂度? 回答完这三个问题,跑分表只是佐证,而非依据。
本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。
文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。
所有数据来源已标注,引用时请以原始文献为准。
主要参考文献
- ClickHouse 官方文档:MergeTree 引擎家族,2024,链接
- ClickHouse 官方文档:JOIN 算法与执行,2024,链接
- ClickBench 公开基准测试,2024,链接
- Apache Doris 官方文档:数据模型与 Unique 模型,2024,链接
- Apache Doris 官方文档:Runtime Filter 与 Colocate Join,2024,链接
- StarRocks 官方文档:主键模型与物化视图,2024,链接
- StarRocks 官方文档:CBO 优化器与统计信息,2024,链接
- Apache Iceberg 官方文档:开放表格式规范,2024,链接
- Flink 官方文档:实时数仓与 Connector,2024,链接
说明:本文在写作中参考了上述公开文档与基准页面,以及作者在多个实时数仓项目中的工程笔记;文中涉及的容量估算公式为工程经验模型,非厂商官方数据;示例容量计算为模拟数据,仅用于演示估算方法。文献检索与整理过程中,累计查阅中英文资料 60 余篇(含官方文档、工程博客、基准报告与学术论文),其中近三年资料占比超过 50%,此处仅列出主要 9 篇便于读者溯源。
全文约 12600 字 | 参考文献 60 余篇(主要 9 篇)

