专业书籍精读 · DDIA · 第 3 章

存储与检索

Designing Data-Intensive Applications · Ch 3 · Martin Kleppmann · 2017

EN →

这一章讲什么?

你在淘宝下的单、在微信发的消息,最后都要落到某块硬盘上某个位置,而且下次你一刷,它还得能被飞快找回来。数据库底层干的就是这两件事:怎么把数据存下去、怎么再把它捞出来。DDIA 第 3 章掀开盖子,讲两种截然不同的「存法」,以及为什么「给人用的数据库」和「给分析用的数据库」骨子里就不是一路货。

先打个比方

把数据库想成一个记账的人,他有两种记账风格。流水账派:来一笔就往本子后面添一行,从不翻回去改旧账;小本子记满了,就誊成一本「按字母排好序」的大账本存起来,夜里再把几本旧账合并整理。活页夹派:一个按字母分好格的活页夹,要改哪条就翻到那一页、擦掉重写。两种都能用,但脾气完全不同——一个写得飞快,一个找得稳当。

最笨的数据库,与「目录」的代价

最偷懒的存法就是流水账:每条都往文件末尾一加,写得快极了。可你要找一条,就得从头翻到尾——数据一多就慢成灾。于是要建目录(索引):像书后面的索引,帮你「按名字直接翻到那一页」。但天下没有白吃的午餐:多一本目录,找得快了,可你每写一笔都得顺手更新目录,写就变慢了。所以数据库不会替你把什么都编进目录,得你自己挑。

两派的脾气

流水账派(数据库界叫 LSM)写得飞快,因为它永远只往后添、从不回头改;代价是找一条可能要翻好几本账,而且它后台合并旧账本时,会偶尔跟你正常的读写抢硬盘,让个别请求卡一下。活页夹派(就是大名鼎鼎的 B-tree)找得稳、改得利落、每条只住在一个格子里;代价是写一笔要翻回原地擦了重写,而且每页都留点空白、有点浪费。Facebook 曾把社交数据从活页夹派换成流水账派,硬盘占用直接砍掉六成

分析型数据,要「竖着存」

平时数据库按「一个人一整行」存:查你这个人的全部信息很快,一行全在一块儿。可老板要「所有用户的平均年龄」,就得把几亿行整个翻一遍、每行却只用到「年龄」那一个字段,白读一大堆没用的。所以专门做分析的数据库反着来——按列竖着存:把所有人的「年龄」堆在一起、所有人的「城市」堆在一起。算平均只读年龄那一条;而且同一列长得像(都是年龄数字),还能压得特别小。这就是为什么公司做报表要另建一个「数据仓库」,而不在你日常用的库上直接跑。

一句话记住

数据库存数据无非两大流派:流水账(写飞快、后台要合并)和活页夹(读稳当、原地改);再看用途——给人用的按行存,给分析用的按列存。选对底层,同一个查询可能快上几十倍。

想进到具体机制、结构图和真实系统? → 切到精读版