IT 论文精读 · PAPER 23

Dremel:秒级交互式查询万亿行

Melnik 等 · Google · VLDB 2010

EN →

这篇论文干了什么?

2010 年,谷歌公开了内部一个叫 Dremel 的系统。它能让工程师对着一张上万亿行的巨表随手敲一句查询——「过去一小时哪些网页被点得最多?」——然后几秒钟就把答案端上来。这在当时几乎是魔法:同样的活,用之前的批处理工具(MapReduce)得跑上几分钟甚至几小时。今天谷歌云上人人可用的 BigQuery,底子就是它。

先说个痛点

数据大了以后,「问一个问题」变得很慢。传统数据库是一行一行存的:一条记录的所有字段(网页地址、标题、点击数、时间……)挨在一起。可你想算的往往只是某一列(比如「所有网页的点击数之和」)。一行一行地存,就逼着机器把每条记录整条读进来、再从里面抠出那一个数——绝大部分读进来的东西都白读了,像为了看一本书里的页码,把每一页整页都翻一遍。

第一个点子:按列存,不按行存

Dremel 反过来:把同一列的值全都集中放在一起。所有网页的「点击数」排成一长条、所有「标题」排成另一长条。这样算「点击数之和」时,机器只去读那一条、其它列碰都不碰——该读的一点不少,不该读的一点不碰。而且同一列的数长得像(都是数字、都是网址),挨在一起特别好压缩,读起来更快。

难点在于:谷歌的数据不是规规矩矩的表格,而是层层嵌套的——一个网页记录里套着「多个作者」,每个作者又套着「多种语言」,像一个俄罗斯套娃、又像一份带二级三级子目录的清单。这种「套娃数据」怎么拆成一条条平整的列、事后还能原样拼回去?Dremel 的办法是:给列里每个值额外记两个小标签,一个记「它属于第几层套娃」、一个记「它是新一组的开头、还是上一组的续」。靠这两个标签,散开的列随时能无损还原成原来的套娃结构。这套编码是它最硬核、也最被后人抄去的贡献。

第二个点子:把查询摊给几千台机器

光按列存还不够快。Dremel 借了搜索引擎的架子:一句查询进来,先到「根服务器」,它把活拆开、往下发给一批「中间服务器」,再往下发给成千上万台「叶子服务器」——每台只啃整份数据的一小片、各算各的局部答案(比如「我这片的点击数之和」)。然后局部答案顺着这棵树一层层往上汇总、合并,到根服务器就拼成最终结果。几千台机器同时开工,万亿行于是几秒扫完。

带来了什么

它让「查大数据」从「提交任务、去喝杯咖啡等结果」变成了「敲一句、看一眼、再改一句」的交互式探索。数据分析师第一次能像用小数据库那样,对着 PB 级的数据来回追问。它催生了 BigQuery,也把那套「嵌套数据的列式编码」变成了整个大数据界的通用格式(如今开源的 Parquet、ORC 都是这条路)。

诚实一句:Dremel 快,是因为它只擅长一件事——大规模「扫一遍、做统计」的只读分析;它不改数据、不做事务,早期也几乎不支持大表之间的复杂关联,不是用来替代普通数据库的。

一句话记住

把嵌套数据按列拆开存(配两个小标签保证能无损拼回)、再借搜索引擎的多级树把查询摊到几千台机器并层层汇总——于是万亿行也能几秒出结果,把「查大数据」变成了交互式探索。这就是 BigQuery 的地基。

想看列式编码的两个「层级」标签怎么工作、执行树长什么样、跑多快? → 切到精读版