列式存储即规范化

Hacker News Top 论文

摘要

本文将列式存储重新定义为数据库规范化的极端形式,展示了把属性拆分为位置对齐的数组如何与基于隐式序数主键连接的规范化表如出一辙。

暂无内容
查看原文 导出为 Word 导出为 PDF
查看缓存全文

缓存时间: 2026/04/22 13:13

# 列式存储就是规范化 来源:https://buttondown.com/jaffray/archive/columnar-storage-is-normalization 我以前一直没意识到,把行式数据转成列式数据,并不是数据库领域里什么全新的概念,它仍然属于关系抽象的一部分——或者说,可以被看作是关系抽象。 举个例子,我们有这样一份数据: ```json data = [ { "name": "Smudge", "colour": "black" }, { "name": "Sissel", "colour": "grey" }, { "name": "Hamlet", "colour": "black" } ] ``` 这相当于关系数据库里的一张表。假设它真的存在数据库里,每次访问任意字段都得做磁盘 IO。这种表示法有一些优点: - **加行方便**:只要拼出一行 `{ "name": "Petee", "colour": "black" }`,追加到列表末尾即可;磁盘上可能只需改几个页。即使这一行有几十列,也依旧如此。 - **查行迅速**:因为同一行的所有列在物理上紧邻,把整行捞出来很快。 反过来,如果想统计宠物颜色的直方图,就得把大量无关数据(比如名字)一起读进来——效率很低。 这就是**行式存储**。换成**列式存储**,数据长这样: ```json data = { "name": [ "Smudge", "Sissel", "Hamlet" ], "colour": [ "black", "grey", "black" ], } ``` 优缺点正好反过来:只关心 `colour` 时,可以只读这一列,名字一字节都不用碰;但改数据或按行查询就麻烦——要到处跳。如果想拿第二行,就得去每个列数组的第二个位置把字段拼回来。 一种理解是:这只是**编码层**的事,位于数据模型之下;SQL 引擎逻辑上区分不了两种格式,只能通过查询性能感知差异。 另一种理解是:**列式化就是一种极端的数据库规范化**。 不再是一张“宽表”对应一堆向量,而是把每列拆成一张小表,主键再加一个属性: 非规范化表: ``` +----+------+-----+ | id | name | age | +----+------+-----+ | 12 | Bob | 30 | | 93 | Tom | 35 | | 27 | Kim | 28 | +----+------+-----+ ``` 规范化后: ### Name 表 ``` +----+------+ | id | name | +----+------+ | 12 | Bob | | 93 | Tom | | 27 | Kim | +----+------+ ``` ### Age 表 ``` +----+-----+ | id | age | +----+-----+ | 12 | 30 | | 93 | 35 | | 27 | 28 | +----+-----+ ``` 用 `id` 做 join 就能拼回原表。 在列式存储里,可以把“主键”看成数据在数组里的**下标**。 原数据: ```json data = { "name": [ "Smudge", "Sissel", "Hamlet" ], "colour": [ "black", "grey", "black" ], } ``` 可以视为: ``` +----+--------+ | id | name | +----+--------+ | 0 | Smudge | | 1 | Sissel | | 2 | Hamlet | +----+--------+ +----+--------+ | id | colour | +----+--------+ | 0 | black | | 1 | grey | | 2 | black | +----+--------+ ``` 但 `id` 其实只是数组下标,可以隐去: ``` +--------+ | name | +--------+ | Smudge | | Sissel | | Hamlet | +--------+ +--------+ | colour | +--------+ | black | | grey | | black | +--------+ ``` 这种视角的价值在于:它把传统的投影、join 等查询操作,与数据格式的转换统一了起来。大多数时候,你确实应该把数据格式当成对查询逻辑透明的实现细节;但心里要明白——**“从列存里拼回一行”不仅看起来像 join,它本身就是 join。**

相似文章

对 APL 等数组语言的有原则性重新思考

Lobsters Hottest

本文提出了一种有原则性的方法来重新思考 APL 等数组语言,通过将变量建模为输入维度的函数,旨在相较于传统方法提高可读性和错误检查能力。

PriorLabs/TabPFN

GitHub Trending (daily)

PriorLabs 推出了 TabPFN,这是一种专为表格数据设计的基座模型。

稀疏 Cholesky 消元树

Hacker News Top

本文推导了面向右侧的稀疏 Cholesky 算法的列消元树,解释了它如何在不进行稠密分解的情况下预测填充元素和任务依赖关系。