理解数据库模型:DDIA 第2章
看起来您只提供了来源链接,而没有贴出需要翻译的正文内容。请把您想要翻译的文本粘贴在这里,我会按照要求保留链接并将正文翻译成简体中文。
概述
本章摘自 Designing Data‑Intensive Applications,探讨了不同的数据库模型以及构建应用数据的策略。理解这些概念对于在现代软件开发中做出明智的架构决策至关重要。
从应用程序角度看数据流
- Collect 收集真实世界的数据。
- Model 使用数据结构和 API 对其建模。
- Store 将其存储在数据库中,数据库可能使用 JSON/XML 文档、关系表或图模型——最终以磁盘上的字节形式持久化。
关系型 vs. NoSQL
在讨论各种数据模型时,关系模型已被证明最具韧性,并且仍被广泛使用。现代应用程序常常将关系数据库与非关系数据库(多语言持久化)结合使用,以满足特定需求。
NoSQL 的优势
- 对大数据集提供更高的可扩展性和写入吞吐量
- 可用的开源选项更多
- 支持关系数据库无法实现的查询
- 更宽松的模式限制
- 对特定用例提供更佳性能,更贴合应用数据结构
阻抗失配与 ORMs
大多数应用程序代码使用面向对象编程,将数据表示为对象。然而,关系型数据库以表、行和列的形式存储数据,形成一个尴尬的转换层,称为 阻抗失配。
对象关系映射器(ORM)通过消除手动 SQL 查询提供帮助,但它们主要提供抽象,而未真正解决根本问题。
文档模型(NoSQL)
文档模型将数据存储为灵活的半结构化文档(JSON/XML),而不是僵硬的行和列。MongoDB 是一个流行的例子。
一对多示例
考虑一个 LinkedIn 个人资料,其中一个用户拥有多个职位。早期的 SQL 数据库在处理这种关系时遇到困难,因为它们并未设计为在一行中存储多个值。开发者为职位创建了单独的表,尽管现代 SQL 数据库现在已经支持多值字段。
文档模型能够优雅地处理这种情况,因为 JSON 相比多表模式提供了更好的局部性。无需在多个表之间发出多次查询,只需一次查询即可检索所有相关数据。
规范化和 ID 引用
在存储用户输入(如城市、组织或学院)时,使用 ID 引用而不是原始字符串(例如 org_id = 5 而不是 org = "Microsoft")。这种做法:
- 自然地建模多对一关系(多用户对应一个组织)
- 通过下拉列表实现干净的数据验证
- 消除重复名称导致的歧义
- 提高可维护性(一次更新,处处生效)
- 允许集中式更改,而无需触及成千上万的记录
想深入了解规范化和模式设计,请参阅我的详细博客 database normalization。
联接
联接将关系型数据库中不同表的字段组合在一起。虽然在 SQL 中这很直接,但文档模型的联接支持要么很弱,要么根本不存在。没有数据库层面的联接时,你必须在应用代码中模拟它们,这会产生性能开销,并将复杂性从存储层转移到应用层。
SELECT * FROM animals WHERE family = 'Sharks';
历史数据模型
层次模型
第一种数据库模型,使用于 IBM 的 IMS,采用单父节点的树形结构——非常适合一对多关系。
限制
- 不支持多对多关系
- 反范式化决策困难
网络模型
为了解决层次模型的局限性而创建,网络模型允许多个父节点,支持多对一和多对多关系。
致命缺陷: 记录通过“访问路径”像编程指针一样相连。这些访问路径使查询和更新极其复杂,抵消了多关系支持的优势。
关系模型的成功
- 将数据存储在简单的表格(行和列)中
- 消除复杂的访问路径
- 优雅地支持多种关系
- 插入行时无需考虑外键问题
改变游戏规则的是 查询优化器 的引入,使编写高效查询变得简单。
声明式 vs. 命令式查询
- 命令式代码 告诉计算机每一步:遍历列表、检查条件、向数组中推入元素——就像提供逐步导航指示。
- 声明式查询(例如 SQL)指定 你想要的是什么,而不是 如何获取。数据库会决定最优的执行计划。
声明式语言天生具备并行化的特性,因为执行顺序不由程序员指定,这使得数据库能够自动将工作分配到多个核心上。
关键要点
- 关系型数据库仍然占主导地位,但在特定用例下可与 NoSQL 良好协作。
- 文档模型在一对多关系上表现出色,具有更好的数据局部性。
- 使用 ID 进行规范化可防止数据重复并简化维护。
- 声明式查询能够实现数据库层面的优化和并行化。
- 了解历史模型(层次模型、网络模型)有助于理解现代解决方案。