题记与说明
- 日期:2026-11-04
- 形式:主题研究(先检索并在线精读 5 个来源,再加本地既有知识交叉比对)
- 章节定位:《DDIA》第一部分"Foundations of Data Systems(数据系统基础)"中专门讲数据模型的一章——第 1 版为第 2 章 "Data Models and Query Languages",第 2 版(2025–2026 更新的中文译本)扩写为第 3 章 "数据模型与查询语言"(章节号前移一位,内容大幅扩充)。本笔记以第 1 版第 2 章为主线,标出第 2 版的重要增量。
- 本次阅读的来源(全部在线精读):
- O'Reilly 官方书页 · Chapter 2: Data Models and Query Languages(第 1 版英文原文预览 + 全章小节目录)(Martin Kleppmann, O'Reilly Media, 2017-03)
- DDIA 第 2 版中文全译 · 第 3 章 数据模型与查询语言(Vonng 译,ddia.vonng.com,页面更新于 2026-10-15)(GitHub: Vonng/ddia)
- Timilearning · DDIA Chapter 2 Notes(第 1 版读书笔记,2019-12)
- Sayed Alesawy · DDIA Ch2 Deep Dive Part 1(关系 vs 文档) 与 Part 2(查询语言与图模型)(Hashnode 系列)
- Dev.to · Understanding Database Models — DDIA Chapter 2(faizanfirdousi)
- Dan Lebrero · Book notes: Designing Data-Intensive Applications(第 1 版要点交叉核对,2021-09-01)
0. TL;DR
这一章回答一个看似简单的问题:该用什么形状来装你的数据? Kleppmann 的答案不是一个模型名,而是一套判据:先看数据里主导的关系形态——一对多的树状结构(简历、订单、用户资料)文档模型最自然;简单的多对一/多对多关系关系模型足够;一旦数据"任何东西都可能和任何东西相关"(社交图谱、知识图谱、组织架构),就该上图模型。历史上这场竞赛已经跑过一轮:层次模型(树)→ 网状模型(指针互联)→ 关系模型靠查询优化器胜出,而 NoSQL 的文档模型某种意义上是层次模型的螺旋回归。另一条主线 equally重要:声明式查询语言(SQL/Cypher/SPARQL/Datalog)让"查什么"与"怎么查"解耦,把优化和并行的自由还给了数据库——同一个图查询,Cypher 4 行,SQL 递归 CTE 要 31 行。无模式(schemaless)是个误导性说法,准确的说法是读时模式 vs 写时模式,类比动态类型 vs 静态类型。两个阵营正在融合:关系数据库加 JSON,文档数据库加 join 和二级索引——"关系模型与文档模型的混合是一种强大的组合"。
1. 核心问题
本章要解决的核心问题是:数据模型不是存储细节,而是"解题思路"的塑造者——那么在关系、文档、图等模型之间,依据什么来选择? 拆开是四个子问题:
- 表达力问题:同一份真实世界数据(人员、组织、商品、行为),用关系表、JSON 文档还是图的顶点和边来建模?哪些操作在一种模型里容易、在另一种里别扭?
- 阻抗不匹配问题:面向对象代码里的对象与数据库的表/行/列之间的转换层(ORM 能否彻底解决)?
- schema 问题:数据库该不该强制数据结构?写时强制(schema-on-write)与读取时解释(schema-on-read)各自的代价与适用场景?
- 查询语言问题:为什么声明式(declarative)查询语言是数据库给应用层的核心红利?MapReduce 这类"代码即查询"的方式处在什么位置?高度互联的数据用什么语言查才不别扭?
章首题词与开篇(第 1 版英文原文,O'Reilly 官方预览页):
> "The limits of my language mean the limits of my world." — Ludwig Wittgenstein, *Tractatus Logico-Philosophicus* (1922)
> "Data models are perhaps the most important part of developing software, because they have such a profound effect: not only on how the software is written, but also on how we think about the problem that we are solving."
2. 主要主张
2.1 分层数据模型:每一层的唯一关键问题是"如何用低一层表示"
第 1 版开篇给出四层叠放(O'Reilly 预览页原文,编号照录):
- 应用开发者把现实世界(人、组织、商品、行为、资金流、传感器……)建模为对象/数据结构 + 操作它们的 API(通常应用特有);
- 存储时用通用数据模型表达:JSON/XML 文档、关系表、或图模型;
- 数据库工程师决定如何在内存/磁盘/网络的字节上表示这些文档、关系或图;
- 更低层,硬件工程师用电流、光脉冲、磁场表示字节。
中文译本(第 2 版):"每个层都通过提供一个明确的数据模型来隐藏更低层次中的复杂性。这些抽象允许不同的人群有效地协作,例如数据库厂商的工程师和使用数据库的应用程序开发人员。"
关键推论:每一层模型都内嵌了"它会被怎么用"的假设——某些操作快、某些操作别扭。选模型就是在选哪些操作是"一等公民"。
2.2 历史循环:文档模型是层次模型的回归,关系模型赢在查询优化器
- 时间线(综合 O'Reilly 小节目录 "Are Document Databases Repeating History?"、dev.to 与 Vonng 译文):1970s–80s 初,层次模型(IBM IMS:树、单亲节点,一对多自然、多对多别扭)与网状模型(CODASYL:多亲节点,但靠"访问路径"指针导航,查询与更新极其复杂)是主角 → 关系模型(Edgar Codd, 1970:"数据被组织成关系……每个关系都是由元组构成的无序集合",中文译文)胜出——dev.to 总结其 game-changer 是查询优化器:删掉访问路径,让声明式查询自动选执行计划 → 80 年代末对象数据库、2000s XML 数据库都"曾盛极一时,但无一长久"。
- NoSQL 的四大动因(第 1 版,经 timilearning 笔记与 hashnode part 1 复述):(a) 大数据集/高写入吞吐的可伸缩性需求;(b) 偏好免费开源软件胜过商业数据库;(c) 关系库不支持的特殊查询操作;(d) 对关系 schema 僵化的不满。
- 文档模型与层次模型的相似性是本章刻意点破的历史呼应:JSON 文档正是"树",IMS 当年处理的也是树。
- 第 2 版补充:"NoSQL 并非某项特定技术,而是围绕新数据模型、模式灵活性、可伸缩性和开源许可模式形成的一组宽泛理念",而"关系模型的每个竞争者都曾盛极一时,但无一长久。反倒是 SQL 在关系模型这个核心之上不断吸收其他数据类型,例如增加了对 XML、JSON 和图数据的支持。"
2.3 对象-关系阻抗不匹配:ORM 是止痛药,不是解药
中文译文(第 2 版):"数据若存储在关系表中,就需要一个笨拙的转换层,在应用代码中的对象与数据库的表、行、列模型之间来回转换。两种模型之间的这种脱节,有时称为*阻抗不匹配*(impedance mismatch)。"(术语借自电子学:阻抗不匹配导致信号反射。)
第 2 版把 ORM 的账算得很细(第 1 版只有一段,这是重要增量):ORM 本身复杂且无法彻底掩盖两种模型差异;只覆盖 OLTP 场景;自动生成的模式未必友好;且容易引入 N+1 查询问题——取 N 条评论后再逐条查作者,本可在数据库里一次 join 完成。JSON 文档之所以让人觉得"更自然",正是因为它贴着应用对象结构。
2.4 关系形态定模型:一对多 → 文档;多对一/多对多 → 引用与 join
贯穿案例是 LinkedIn 简历(第 1 版图 2-1;第 2 版图 3-1,示例数据甚至换成了 Obama 的简历):
- 关系版:
users表 +positions/education/contact_info子表外键关联;JSON 版:整份资料一个文档,树状结构一目了然。 - 多对一(
region_id)与多对多(人 ↔ 组织)很难塞进自包含文档:要么存文本(反规范化、同名义歧义、更新要改所有副本),要么存 ID(但文档库 join 弱,只能应用代码里二次查询或用$lookup)。 - 规范化 vs 反规范化的权衡(中文译文原话):"规范化数据写入较快(因为只有一个副本),查询却较慢(因为需要连接);反规范化数据通常读取较快(连接更少),写入代价却更高(要更新更多副本,也占用更多磁盘空间)。"
- 第 2 版新增一个精彩的现实案例:X(Twitter)的物化时间线只存帖子 ID 和用户 ID,读时再"补全 ID"(hydrating IDs)——因为点赞数/头像变化太快,反规范化进去不划算;同时也证明"读取时执行连接并不妨碍构建高性能、可伸缩的服务"。
2.5 无模式是误导:读时模式 vs 写时模式
中文译文(第 2 版):"文档数据库有时称为*无模式*(schemaless),但这具有误导性,因为读取数据的代码通常假定某种结构——即存在隐式模式,只是不由数据库强制执行。一个更准确的术语是*读时模式*(schema-on-read,数据结构是隐含的,只有读取时才会解释),与之相对的是*写时模式*(schema-on-write,关系数据库的传统做法:模式是明确的,数据库确保写入的所有数据都符合模式)。"
- 类比:读时模式 ≈ 动态(运行时)类型检查;写时模式 ≈ 静态(编译时)类型检查——与编程语言之争同构,没有绝对答案。
- 改字段的代价对比:文档库只需开始写新格式 + 读代码兼容旧格式;关系库要
ALTER TABLE+ 可能全表UPDATE(大表很慢),但"添加带默认值的列也又快又稳妥"(第 2 版提到 pt-online-schema-change、gh-ost、pgroll 等在线迁移工具)。 - 读时模式的甜点区:异构数据——对象类型繁多到无法一表一类、数据结构由你控制不了的外部系统决定。
2.6 局部性:文档模型最大的性能论据,且有边界
- 文档通常存成单个连续字符串(JSON/BSON),一次读取整个文档时避免了关系模型的多索引查找与磁盘寻道。
- 边界(中文译文):"局部性优势只适用于同时需要文档中相当一部分内容的情况。即使只访问大型文档的一小部分,数据库通常也要加载整个文档,这会造成浪费;更新时一般还要重写整个文档。因此,通常建议让文档保持较小,并避免频繁地对文档做小幅更新。"
- 局部性并非文档专利(第 1 版即有、第 2 版保留并扩展):Google Spanner 允许表行交错嵌套(interleave)在父表中;Oracle 有多表索引集群表;Bigtable/HBase/Accumulo 的列族(column family)管理类似局部性。
2.7 融合:两个阵营正在互相学习
中文译文(第 2 版):"这种融合对应用程序开发人员来说是件好事,因为关系模型和文档模型能够在同一个数据库中结合使用时,最能发挥各自所长。……关系模型与文档模型的混合是一种强大的组合。"
- 关系库加 JSON 类型、文档内取值索引;MongoDB/Couchbase/RethinkDB 加 join、二级索引、声明式聚合管道。
- 第 2 版点出一个漂亮的历史注脚:Codd 1970 年的原始论文其实允许"非简单域"(nonsimple domain)——一行里的值可以是嵌套关系,"这与三十多年后加入 SQL 的 JSON 或 XML 支持非常相似"。
- 第 1 版的判断句(timilearning 笔记转述):两个模型"becoming more similar over time"——第 2 版的 2026 年现实(PostgreSQL JSONB、MongoDB
$lookup)证明了这个预言。
2.8 声明式 vs 命令式:数据库给应用层的最大红利
- 贯穿案例:海洋生物学家统计每月观察到的鲨鱼。命令式(Ruby 循环遍历 animals 判断
family == 'Sharks')vs 声明式(关系代数σ_family='Sharks'(animals),SQL 几乎逐字对应)。 - 声明式的三个好处(hashnode part 2 复述第 1 版):更简洁通用;隐藏引擎实现——优化器换索引/换连接算法/换执行顺序,查询一个字不用改(imperative 代码可能悄悄依赖数据顺序);天然可并行——并行是引擎的事,不是程序员的事。第 1 版还用 HTML/CSS 作类比("Declarative Queries on the Web" 小节):CSS 选择器选中元素的方式让引擎自由优化。
- MapReduce 处在两者之间(第 1 版):过滤部分是声明式(MongoDB
query: {family: "Sharks"}),但 map/reduce 是自定义代码;约束是必须纯函数——无副作用、不能再查库,这样框架才能任意乱序、任意重试地跑。第 2 版已经把 MapReduce 从本章移除(MongoDB 官方也已弃用),改为聚合管道$match+$group,并评论聚合管道"表达能力与 SQL 的一个子集相当",语法之争"或许只是口味问题"——这本身是该章内容随产业演化的重要证据。
2.9 图模型:当"任何东西都可能和任何东西相关"时
中文译文(第 2 版总结):"*文档模型*主要关注自包含的 JSON 数据文档,而且文档之间的关系非常稀少。*图数据模型*用于相反的场景:任意事物都可能与其他一切事物相关,查询可能需要跨越多跳才能找到感兴趣的数据。"
- 贯穿案例:Lucy(生于爱达荷,现居伦敦/欧洲)与 Alain 的社交/家谱图。查询:"找出所有从美国移居欧洲的人"——难点在
LIVES_IN边指向的地点层级不定(城市/地区/州/国家),需要变长路径遍历。 - 属性图:顶点 = ID + 标签 + 出边 + 入边 + 属性;边 = ID + 尾顶点 + 头顶点 + 标签 + 属性。三个关键特性(中文译文):"任何顶点都可以通过边连接到任何其他顶点";"给定任意顶点,都能高效地找到它的入边和出边,从而双向*遍历*图"(这就是 edges 表要对
tail_vertex和head_vertex各建一个索引的原因);标签让"一个图中存储多种不同的信息"。Facebook 单一图里人/地点/事件/签到/评论混存,是异质图的最佳例证。 - Cypher(Neo4j/openCypher,名字来自《黑客帝国》角色):
(person) -[:BORN_IN]-> () -[:WITHIN*0..]-> (:Location {name:'United States'})用*0..优雅表达变长遍历。证据性的对比(中文译文):"同一个查询用 Cypher 只需 4 行,用 SQL 却要写 31 行,这恰恰说明选对数据模型和查询语言会带来多大差别。"(SQL 那边是WITH RECURSIVE递归 CTE,写起来"十分笨拙"。) - 三元组存储与 SPARQL:一切皆(主语, 谓语, 宾语);宾语是字面量就是属性,是另一个顶点就是边。RDF 为互联网级数据交换设计(谓语用 URI 防命名冲突),SPARQL 早于 Cypher 且启发了它,同一查询同样简洁。语义网本身没成,但留下了 Wikidata、schema.org、JSON-LD 等遗产——"即使你对语义网毫无兴趣,三元组仍可以成为很好的应用内部数据模型"。
- Datalog:最古老(1980s 学术界),基于关系模型却最擅长图递归;用规则(
:-)逐条搭建派生表,规则可递归调用自身,"就像把代码拆成彼此调用的函数"。第 2 版补 GraphQL 一节:GraphQL 是面向客户端 UI 的受限查询语言(不允许递归、查询来自不受信来源要防 DoS),"其实可以构建在任何数据库之上"。 - 第 2 版还预告标准化的收编:计划把图查询语言 GQL 加入 SQL 标准(借鉴 Cypher/GSQL/PGQL)。
2.10 第 2 版的两个大增量(第 1 版没有):事件溯源/CQRS 与数据框
- 事件溯源与 CQRS:以不可变事件日志为权威数据源(写入最优化),派生出多个读取优化的物化视图(读取最优化);视图必须可从事件日志确定性重算。优点:事件表达"为什么发生"、可重算可调试、天然审计日志;缺点:外部数据(如汇率)破坏确定性、GDPR 删除权与不可变日志冲突、副作用重放要小心。
- 数据框与数组:R/pandas/Spark 的 dataframe"乍看像关系表",但"通常不是通过 SQL 之类的声明式查询来操作,而是通过一系列命令逐步修改其结构和内容",且能自然走向稀疏矩阵/独热编码,"在数据库与多维数组之间架起了桥梁"——这是机器学习时代补上的一块拼图。
3. 方法
书本身的论证方法(值得单独学):
- 分层抽象框架开题:先把"数据模型"定义为层与层之间的表示契约,之后所有比较都挂在这个框架上;
- 历史叙事:层次/网状 → 关系 → NoSQL → 融合,用"历史是否在重复"来检验每个新主张("Are Document Databases Repeating History?" 小节标题本身就是论点);
- 单一贯穿案例反复变奏:LinkedIn/Obama 简历跑完关系版、JSON 版、多对多版、规范化版;鲨鱼观察跑完 SQL 版、MongoDB 版、MapReduce 版;Lucy/Alain 图跑完 Cypher、SQL、SPARQL、Datalog 四种语言——同题多解,差异自己浮现;
- 代码即证据:4 行 vs 31 行的对比不靠形容词,靠把两段代码完整摆出来;
- 刻意不下绝对结论:每个权衡都给出甜点区与失效条件(局部性的边界、读时模式的适用条件)。
我本次的精读方法:先 WebSearch 定位来源 → 精读 O'Reilly 官方预览页拿到第 1 版英文原文开头、章节题词与完整小节目录(作为结构基准)→ 精读 Vonng 第 2 版中文全译拿到全文级细节与中文引述 → 用 timilearning、hashnode ×2、dev.to 三份第 1 版笔记交叉核对(尤其 MapReduce、NoSQL 四动因、历史模型等第 2 版已改写的部分)→ 明确标注两版差异,避免把第 2 版内容错安到第 1 版章名下。
4. 数据与证据
本章证据是例证性/代码对比性的,不是实验测量,具体包括:
| 证据 | 内容 | 来源 |
|---|---|---|
| 章节结构 | 第 1 版三大节:Relational Model Versus Document Model(含 The Birth of NoSQL / The Object-Relational Mismatch / Many-to-One and Many-to-Many / Are Document Databases Repeating History? / Relational Versus Document Databases Today)、Query Languages for Data(含 Declarative Queries on the Web / MapReduce Querying)、Graph-Like Data Models(Property Graphs / Cypher / Graph Queries in SQL / Triple-Stores and SPARQL / The Foundation: Datalog) | O'Reilly 官方小节目录 |
| 原文开篇 | "Data models are perhaps the most important part of developing software…" + 四层模型清单 | O'Reilly 预览页正文 |
| 简历案例 | 关系模式(users + positions/education/contact_info 外键)vs JSON 文档;region_id 用 ID 还是文本的规范化论证;多对多需 associative table | Vonng 译文图 3-1/3-3/示例 3-1/3-2;hashnode part 1 |
| 鲨鱼查询 | PostgreSQL date_trunc('month',…)+GROUP BY vs MongoDB $match+$group 聚合管道 | Vonng 译文 §文档的查询语言 |
| 代码行数对比 | 同一"美国→欧洲移民"查询:Cypher 4 行 vs SQL WITH RECURSIVE 31 行(含环处理、遍历顺序等更多细节"这还只是开始") | Vonng 译文示例 3-5/3-6 及原文评述 |
| ORM 批判清单 | 复杂度高、只覆盖 OLTP、生成模式不友好、N+1 查询问题;以及对应的优势清单 | Vonng 译文 §ORM |
| 在线迁移工具 | pt-online-schema-change、gh-ost、pg-osc、pgroll 等 4 篇参考文献 | Vonng 译文脚注 21–24 |
| 局部性反例组 | Spanner 表交错、Oracle 多表索引集群表、Bigtable/HBase 列族 | Vonng 译文脚注 25–27 |
| 图模型实现组 | Neo4j/Memgraph/KùzuDB(属性图);Datomic/AllegroGraph/Blazegraph(三元组);Amazon Neptune 两者都支持 | Vonng 译文 §图数据模型 |
| 第 2 版产业佐证 | MongoDB 弃用 mapReduce 改聚合管道;GQL 进 SQL 标准计划;Stonebraker & Pavlo "What Goes Around Comes Around… And Around…"(SIGMOD 2024) | Vonng 译文脚注 31/42 |
证据是否充分:对"模型选择取决于关系形态"这一核心论点,案例充分且相互独立(简历/鲨鱼/社交图三案例覆盖三种形态);但所有性能判断(局部性更快、join 更慢)均为定性论证,无 benchmark 数据——这类结论只能当"经验法则"用。
5. 结论
- 没有普适最优的数据模型。选择判据是数据中主导的关系形态:一对多树状 → 文档模型;简单多对一/多对多 → 关系模型;高度互联、需要变长路径遍历 → 图模型。(第 1 版经验法则,经 hashnode part 1 复述:高度互联数据上,"document is awkward, relational is acceptable, graph is most natural"。)
- 无模式 ≠ 无结构:结构一定存在,区别只在于强制在写入时(显式)还是假定在读取时(隐式)——映射到动态/静态类型之争,答案取决于数据是否异构、由谁控制。
- 声明式查询语言是数据库百年竞争沉淀出的核心红利:它把优化自由还给引擎、把并行自由还给硬件;图查询语言的多样性(Cypher/SPARQL/Datalog/GQL)说明这个红利在关系模型之外同样成立。
- 两个阵营在融合而非替代:关系库 + JSON 文档列、文档库 + join/二级索引,"混合是最强组合";Codd 的 nonsimple domain 说明这一融合甚至是"回到 1970"。
- 第 2 版的增补(事件溯源/CQRS、数据框)把本章的框架从"选一种模型"推进为"写入优化表示 + 派生读取优化表示"的模型组合论——这正是第 1 版第 10–12 章"Derived Data"思想前置到数据模型层面的体现。
6. 局限
作者承认/明示的:
- 本章是概览,"没有足够的篇幅详述每个模型";存储引擎如何实现这些模型(B-tree/LSM)推迟到下一章,编码与演化推迟到第 4/5 章;
- 第 1 版明示并发控制与容错上的差异不在本章讨论范围(hashnode part 1 复述:"Concurrency and fault-tolerance differences… are out of scope for this chapter section");
- 第 2 版总结承认还有一整批模型没讲:基因组序列搜索(GenBank)、复式记账账本(TigerBeetle)、全文检索等。
我推断的:
- 案例全部来自互联网 OLTP 场景,对嵌入式(SQLite)、科学计算、金融账本等场景只有一句话带过;
- 所有性能权衡无量化数据,"局部性快""join 慢"在不同存储引擎、不同硬件(尤其内存数据库)下结论会翻转;
- 第 1 版 MapReduce 一节已过时(MongoDB 弃用 mapReduce),第 2 版已重写——精读时应以第 2 版为准,但要意识到"哪一版"本身就是这些技术判断的半衰期的证据;
- 本章对事务、隔离级别等"用了文档模型之后才会遇到的麻烦"(跨文档原子性)只一笔带过,容易让读者低估反规范化的运维成本。
7. 对我的启发
结合我已有的笔记体系(PostgreSQL JSONB/MVCC、SQLite、Redis、混合检索、事件驱动消息队列):
- 选型流程模板:拿到建模需求先画"关系形态图"——数一数一对多、多对一、多对多、递归互联各占多少。主导形态直接映射模型选择;这条比"新项目用 MongoDB 还是 PostgreSQL"式的站队问题有用得多。
- PostgreSQL 是"融合论"的最佳现实验证:关系骨架 + JSONB 文档叶 + 两者都可建索引,等于把 schema-on-write 与 schema-on-read 放进同一个库。我的个人项目默认这条路,把"要不要文档库"变成"哪部分字段值得提升为列"。
- 递归关系警惕 SQL 递归 CTE 的 31 行税:组织架构、评论树、BOM 这类变长路径查询,若频率高,评估 WITH RECURSIVE 的可维护性成本 vs 图扩展(如 Apache AGE)或专用图库;低频查询则 31 行也能接受。
- ORM 的 N+1 是文档/关系混用时的经典暗坑:凡是"列表页 + 每行再查关联对象"的代码都值得 grep 一遍;手写 join 或显式 eager loading。
- 反规范化 = 引入衍生数据:一旦决定冗余存储,就必须回答"谁负责保持一致"(应用双写?物化视图?CDC/事件流?)——这一条与第 2 版新增的事件溯源/CQRS 一节、以及 Twitter 时间线案例形成闭环:反规范化的一致性成本正是流处理系统存在的理由。
- 声明式思维可以迁移:设计 Agent 工具 API 或 Prompt 时,同样遵循"说 what,把 how 留给执行引擎"——把排序、过滤、聚合的优化权留给被调用方,接口才不会随实现演进而腐化。
附:本次精读来源链接
- O'Reilly 官方第 1 版第 2 章预览与目录:<https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/ch02.html>
- Vonng《DDIA》第 2 版中文译·数据模型与查询语言:<https://ddia.vonng.com/ch3>(仓库:<https://github.com/Vonng/ddia>)
- Timilearning 读书笔记:<https://timilearning.com/posts/ddia/part-one/chapter-2>
- Hashnode 深读 Part 1:<https://sayedalesawy.hashnode.dev/designing-data-intensive-applications-ch2-data-models-and-query-languages-or-part-1>;Part 2:<https://sayedalesawy.hashnode.dev/designing-data-intensive-applications-ch2-data-models-and-query-languages-or-part-2>
- Dev.to 章节总结:<https://dev.to/faizanfirdousi/understanding-database-models-ddia-chapter-2-36jj>
- Dan Lebrero 要点笔记:<https://danlebrero.com/2021/09/01/designing-data-intensive-applications-summary>
*说明:英文引述取自 O'Reilly 官方页面可见的原文片段;中文引述取自 Vonng 第 2 版中文译文(CC 授权译本);标注"第 1 版"而来源为笔记类站点的内容,均经过至少两个来源交叉核对;未能核对的细节已在文中注明来源层次。*