Vertica 2012 — C-Store 论文走向产品的七年改造账
是什么
Vertica 是 C-Store 学术原型商业化七年后的产物。这篇 2012 年的论文是原班作者 + 工业开发者一起写的”七年回顾”——把 C-Store 的核心想法装进真实客户机房后改了哪些、留了哪些、新加了哪些。日常类比:实验室里跑通的电动车原型车 vs 出厂能交付给消费者的量产车——理论可行,但门把手、空调、保修、撞击测试这些”周边 80%“才是工程量。
C-Store 2005 年那篇论文里讲的列存 + 多 projection + 编码压缩 + WOS/ROS 双层存储 + tuple mover 后台合并这套理论,被验证可行,全部留下。但要让 DBA 敢把 PB 级业务跑上去,原型缺了一大堆边角:自动物理设计、bulk load 通路、K-safety 副本恢复、SQL 兼容、备份/监控/DDL。这篇论文逐项交代了改造历程。
一句话定位:列存数据库从”论文里能跑”到”客户能上线”的差距清单。
为什么重要
不理解 Vertica 这篇论文,下面这些事都没法解释:
- 为什么学术原型(C-Store)和工业产品(Vertica)核心机制名字一样、行为细节差很远
- 为什么后来的 Snowflake / Redshift / ClickHouse 都把”自动选物理布局”做成产品卖点
- 为什么列存数据库都把”加载通路”和”查询通路”做成两条不同代码——WOS/ROS 双层是这个分裂的源头
- 为什么 K-safety 这个名字直到现在还在 Vertica 文档里出现——它绑死了副本设计
- 为什么”工业级列存”不是单点优化能解决的,而是 projection / encoding / 副本 / tuple mover 多层联动
- 为什么读 Vertica 论文比读 C-Store 论文更能学到”产品化思维”——前者被市场打磨过
核心要点
Vertica 在 C-Store 基础上做了 三层关键改造:
-
物理设计自动化:C-Store 论文假设 DBA 自己挑 sort key、自己定 projection。现实里没人会做。Vertica 加了 Database Designer——给它工作负载样本,它输出一组 projection 推荐。类比:买家具时给设计师户型图和生活习惯,设计师返一张布局图,你不用懂家具学。
-
WOS/ROS + tuple mover 落地为真实存储引擎:WOS(Write Optimized Store)是内存里的写入缓冲,ROS(Read Optimized Store)是磁盘上的列存按段排序。tuple mover 后台把 WOS 攒够的批量数据 sort + encode 后落到 ROS。bulk load 走直连 ROS 通路绕过 WOS 抢资源。
-
K-safety 副本 + 恢复:每个 projection 在不同节点上至少存 K+1 份。节点宕机时查询路由到副本继续跑,恢复时从副本拉数据重建。projection 设计要保证不同副本可以是不同排序——这样不同查询模式不会全打到同一类节点。
三层加起来让 C-Store 从论文变成 7×24 跑的产品。
每一层都不是论文式新颖度爆表的发明,但每一层都是真正客户现场摔出来的工程必需品。
实践案例
案例 1:电信运营商的两份排序 projection
某电信公司有一张通话明细表,常见两种查询:按用户 ID 查”这个人最近 30 天通话”,按时间段聚合”昨天 9 点到 10 点全网通话总量”。
CREATE PROJECTION calls_by_user AS SELECT user_id, ts, duration, dst FROM calls ORDER BY user_id, ts SEGMENTED BY HASH(user_id);
CREATE PROJECTION calls_by_time AS SELECT user_id, ts, duration, dst FROM calls ORDER BY ts SEGMENTED BY HASH(ts);同一份逻辑数据,物理上两份不同排序。明细查询走 calls_by_user(按 user_id 排序,prefix scan 极快),时段聚合走 calls_by_time。优化器自己挑——业务代码完全不用知道有几份 projection。
代价是写入要同时维护两份。但分析库写少读多,这笔交易划得来。
案例 2:广告点击日志的编码组合
广告日志的 ad_id 列基数低(几千个广告 ID)、连续多次重复——用 RLE(Run-Length Encoding),存”ad_id=42 重复 1000 次”压成一个三元组。timestamp 列单调递增、相邻差小——用 delta 编码,只存相邻差值。url 列高基数 + 长字符串——用 LZ + dictionary。
ad_id → RLE → 30× 压缩timestamp → delta+frame → 8× 压缩url → LZ+dict → 4× 压缩每列单独选编码是 Vertica 的核心红利——比”整页一种压缩”灵活得多。
更狠的是 RLE 列还能让某些聚合不解压直接算:count 一段 RLE 就是把 run 长度加起来,根本不用还原原始值。
案例 3:日终批跑 ETL 关闭 WOS 直接 bulk load
COPY fact_sales FROM '/data/sales_2026_05_30.csv' DIRECT; -- DIRECT 跳过 WOS,直入 ROSDIRECT 关键字让 ETL 走”绕过 WOS 直接生成 ROS 段”的快通路。代价是装载完之前查询读不到新数据,但 ETL 窗口里没人跑 ad-hoc,没关系。tuple mover 不会被打扰,前台查询和 ETL 各走各的。
这就是 Vertica 把”加载通路”和”查询通路”做成两条不同代码路径的工程价值——能根据时段和负载切换策略。
踩过的坑
-
把 projection 当索引狂加:DBA 听见”projection 是预排序物化视图”就加了 30 个,存储和写入放大双双失控。Vertica 加 Database Designer 是为了硬性剪枝——没工作负载证据的 projection 不准建。
-
WOS 满了不及时 flush 到 ROS:tuple mover 跟不上写入速度时 WOS 持续涨,查询要扫 WOS + ROS 两份数据反而变慢。监控必须盯 WOS 占用率而不是只盯磁盘。
-
编码选错让 CPU 反成瓶颈:高基数列上用 RLE(每行一个 run,全是单元素 run),压缩率倒挂还多花 CPU 解码;低基数列上用 dictionary 但字典超过几千项,查找成本超过收益。Vertica 后来加了自动编码选择——按列统计抽样推荐。
-
K-safety 只保副本数不保排序多样:K=1 表示每份数据存 2 份,但如果两份 projection 都按
user_id排序,按时间的查询模式集体打到一类节点,性能塌方。projection 设计要显式让副本走不同 sort key。
适用 vs 不适用场景
适用:
- OLAP / 数据仓库 / BI 报表 — 列存 + 编码压缩的最佳赛道
- 数据量 TB 到 PB 级 + 查询常聚合少量列 — projection 收益最大
- 有清晰工作负载画像(哪些查询占 80%)— Database Designer 才有发挥空间
不适用:
- OLTP / 事务密集 — 单行更新和点查在列存上是反向收益
- 工作负载完全 ad-hoc 不可预测 — projection 选不了,退化成单一全表 sort
- 数据量小(GB 级)— 行存数据库的索引足够,列存的运维复杂度不划算
- 需要严格毫秒级写入可见 — WOS/ROS 双层 + tuple mover 有内在延迟
历史小故事(可跳过)
- 2005 年:MIT / Brown / Brandeis 几位教授(Stonebraker、Madden、Abadi 等)发表 cstore-2005 论文,主张分析负载该用列存。
- 2005 年:同一批人成立 Vertica 公司商业化 C-Store。
- 2007-2010 年:Vertica 被金融、电信、广告客户陆续部署,发现 C-Store 论文的物理设计假设全靠 DBA 手工,市场不接受,开始造 Database Designer。
- 2011 年:HP 以约 3.4 亿美元收购 Vertica,成为 HP 的分析平台核心。
- 2012 年:Lamb 等原 C-Store 团队和工业开发者联合写下这篇 VLDB 论文,承认学术原型与产品有大段距离,把 7 年工业经验沉淀给学界。
- 2015 年后:MicroFocus 收购 HP 软件部门,Vertica 继续发展;同时 Snowflake / ClickHouse / Redshift 把 Vertica 验证过的列存路线推向云原生。
学到什么
- 理论原型 → 商业产品中间是 80% 的边角工作:DDL、备份、ETL、SQL 兼容、监控、容错、自动调优——每一项都不是论文级新颖度但都是生死线
- “自动化物理设计”是工业列存的真正护城河:从 Vertica Database Designer 到后来 Snowflake 的 micro-partition + clustering,都是这条路
- 每列独立选编码 是列存压缩比的关键来源,不是”整页 LZ”能比的
- 副本数量 ≠ 副本多样性:K-safety 是工程友好但不充分的不变量,要补”副本必须不同排序”
- 加载通路和查询通路要解耦:WOS/ROS 双层 + DIRECT bulk load 旁路,是为了让 ETL 和分析互不抢资源
延伸阅读
- 视频:Andy Pavlo CMU 15-721 — Vertica 工业列存案例课,把 projection / encoding / tuple mover 逐项讲透
- Vertica 文档:Vertica Architecture Overview — 现代版 K-safety / projection 概念
- 论文 PDF:Lamb 2012 VLDB(12 页,工程细节密度高)
- cstore-2005 —— 这篇论文的”上一集”,理论原型
- monetdb-x100-2005 —— 同时代另一条列存路线,强调向量化执行
- snowflake —— 列存 + 自动物理设计在云时代的演进版
关联
- cstore-2005 —— 直接前作,本论文是它的工业续集
- monetdb-x100-2005 —— 平行的列存学派,更偏向 CPU 缓存友好
- snowflake —— 云原生列存数仓,把 Vertica 思路搬到 S3 + 计算存储分离
- system-r-1976 —— 关系型数据库工程化的鼻祖,奠定查询优化器框架
- dewitt-gray-1992 —— 并行数据库经验论,K-safety 副本恢复的思想源头
- stonebraker-2010-sqlnosql —— Stonebraker 同年的”OLTP/OLAP 分家”宣言
- neumann-2015-large-joins —— 现代列存 join 算法,承接 Vertica 时代经验
- leis-2015-optimizers —— 优化器选 projection 的现代方法学
- aurora —— 云端 OLTP 的对照参考,用于理解 OLAP/OLTP 物理分歧
反向链接
- aurora —— Aurora — 把数据库的下半身换成日志机
- cstore-2005 —— C-Store — 把数据按列存,分析查询直接快十倍
- dewitt-gray-1992 —— DeWitt-Gray 1992 — 并行数据库取代专用机的宣言
- duckdb-2019 —— DuckDB — 把 OLAP 数据库塞进你的 Python 进程
- leis-2015-optimizers —— Leis 2015 — 用真实数据打脸所有数据库的查询优化器
- monetdb-x100-2005 —— MonetDB/X100 — 让数据库一次处理一向量行而不是一行
- neumann-2015-large-joins —— Adaptive Optimization of Very Large Join Queries — 100 张表也敢精确求解
- snowflake-2016 —— Snowflake 2016 — 把数仓拆成 storage / compute / services 三层
- stonebraker-2010-sqlnosql —— Stonebraker 2010 SQL vs NoSQL — 慢的是老实现,不是 SQL
- system-r-1976 —— System R 1976 — 第一个跑起来的关系数据库