IT 论文精读 · PAPER 64

C-Store:列式数据库

Stonebraker, Abadi, Madden, Cherniack, O'Neil 等 · MIT / Brandeis / UMass Boston / Brown · VLDB 2005

EN →

这篇论文干了什么?

2005 年,Michael Stonebraker 和一群数据库研究者做了个叫 C-Store 的系统原型,把数据库里的数据从「一行一行地存」改成「一列一列地存」。听起来只是换了个摆法,却让「把上亿条记录汇总成一个数字」这类查询快了两个数量级。今天你用的 BigQuery、Snowflake、ClickHouse,以及数据湖里到处都是的 Parquet 文件,走的都是这条路。

打个比方

把数据库想成超市的账本。传统做法是按收据存:每笔交易的时间、门店、商品、金额写成完整的一张,一张张摞起来。这时老板问一句:「去年全国一共卖了多少钱?」——你只需要「金额」这一个数字,却不得不把每张收据整张抽出来、瞟一眼金额、再塞回去。上亿张收据,力气几乎全花在搬运你根本不看的那些字段上。

新在哪

C-Store 换了个摆法:把所有收据的「金额」抄成一长条,「门店」抄成另一长条,「商品」再抄一条。老板问金额,你就只搬金额那一条,别的碰都不碰。同样一个问题,要搬的东西少了一大截。

怎么做到的

而且这么一摆,还顺手带出三件好事。

一是特别好压缩。一整条里全是同一种东西——门店那条里「北京中关村店」可能一连重复几千行,记一笔「北京中关村店,从第 1 行起,连着 5000 行」就完事了。更妙的是,很多问题压着不解开就能回答:想知道这家店有多少笔交易,看一眼那句「连着 5000 行」即可,根本不用把它摊开还原成 5000 行。

二是同一份数据可以按几种顺序各存一套。常按日期查就排一套按日期的,常按门店查就排一套按门店的——好比同一批账同时按日期、按门店装订了两本,问哪种问题都有一本现成排好的。传统数据库靠「另外建索引」去够到类似效果;这里因为列压得极小,索性多存几套更划算。这几套副本还顺便是备份:坏掉一台机器,从别的副本把它缺的数据重新问出来就行。

三是写入怎么办。排得整整齐齐、又压得死紧的账本,想在中间插一行非常费劲。C-Store 的办法是分成两处:新数据先进一个小小的「随手记」(写得快、不压缩),后台养着一个搬运工,定期把攒够的部分成批合并进那本整齐的大账。读的时候两边一起看,所以不会读丢刚写的数据。

带来了什么

论文里,C-Store 在一组分析型查询上比当时的商用行式数据库快了两个数量级,占的磁盘还不到人家一半。它后来变成一家公司 Vertica(2011 年被惠普收购),而「列式 + 重压缩」从此成了数据仓库的默认长相。

也说句诚实的代价:这套摆法天生是给「写得少、读得多」的分析场景准备的。要一笔笔改订单、改完立刻生效的交易型业务,一行一行地存依然更合适。

一句话记住

按列存,查询就只搬它真正要用的那几列;一整列长得像,于是能压到很小、还能压着不解开直接算;再把同一份数据按几种顺序各存一套,既当索引又当备份;写入慢的问题交给「随手记 + 后台批量合并」。分析型数据库从此换了代。

想看投影、join index、WS/RS 的结构图与实验数字? → 切到精读版