简介
随着时间的推移,数据库被设计成适应多种不同的使用模式、组织层次结构和一致性约束。其中两种最持久的设计是关系型数据库和文档数据库。
在本指南中,我们将探讨这两种数据库模型,以便更好地了解它们的相对优缺点,并评估它们最适合哪些场景。我们将研究它们如何处理数据结构、查询以及在项目中选择使用它们的最终结果。
关系型数据库和文档数据库如何组织数据
关系型数据库与文档数据库的核心区别在于它们所采用的实际数据库模型。数据在管理系统中的存储和组织方式对它们允许的操作类型、哪种访问模式性能最佳以及与应用程序逻辑集成有多么直接有着广泛的影响。
关系型数据库如何构建数据
关系型数据库的数据结构主要通过相关机制的层次结构来定义:数据库、表和列。
数据库本身充当系统中各种表和属性的容器。数据库层允许管理员全局地将策略和属性应用于相关数据集。它们还充当命名空间,以限制表和其他子元素的命名冲突的可能性。
在这些数据库中,数据结构由表定义。表通过声明一组列的名称和属性以及配置表级属性来创建。
每个列都指定一个数据类型,它控制可能存储在其中的数据形状。约束也可以在列和表上声明,这允许你对字段的有效数据施加额外要求。数据本身以行的形式存储在表中。每条记录存储表中每个列的单个值。
总而言之,关系型数据库管理系统 (RDMS) 将相关的表和设置分组到数据库中。每个表通过设置一系列具有数据类型和其他属性的列来定义其可容纳记录的特定结构。记录以行的形式添加到表中,每行记录表中每个列的值。
文档数据库如何构建数据
文档数据库管理系统也通过相关组件的层次结构来组织数据,但采用了一套不同的范式。文档数据库通常使用数据库、集合和文档的系统。
与关系型数据库一样,文档数据库系统使用一个总括的“数据库”抽象来封装相关数据,以实现全局策略和命名空间。数据库层充当一个容器,用于定义广泛的属性、实现内聚的访问控制,并将操作范围限定到相关上下文。
在数据库内部,称为集合的组用于捆绑单个文档。集合比表(它们的关系型对应物)的定义更松散,主要用作容器和额外的作用域机制。
与关系型数据库不同,集合本身不定义它们可以存储的文档的字段或属性。相反,每个文档的结构由其声明的字段和数据隐式定义。因为结构是单个文档的属性而不是集合的属性,所以集合中文档的形状可以有很大差异。符合可理解的结构是数据库用户的责任,而不是数据库系统自行强制的属性。
结构与灵活性之间的相互作用
鉴于这两种设计所采用的不同数据管理理念,用户所获得的结构和灵活性程度存在一些重大差异可能并不令人惊讶。通常,关系型数据库系统倾向于优先考虑结构、可预测性和一致性,而文档数据库则更青睐灵活性、响应性和适应性。
结构刚性的理由
通过使用表,关系型数据库会提前配置其数据的形状。存储在表中的每条记录都必须无一例外地符合表所实现的结构。
要更改数据结构,表结构本身必须更改,并且任何现有记录都需要更新以匹配新结构。这种系统使得结构更改的成本相对较高,因为表中已输入的每条数据都需要更新。这可能意味着更新表中的每条记录、重建索引,并且必须决定如何最佳地回填初始输入时未记录的值。
这种成本使得提前仔细考虑数据结构是明智之举,尽管这可能令人望而生畏。然而,重要的是要记住,这种方法在数据完整性方面提供了极大的保证和安全性。
存储在表中的数据将始终与表定义所要求的程度保持同质。这是一种强制机制,可以帮助你维护组织良好的数据,无需内省每个数据项的个别属性即可对其进行推理。
表结构对你的数据提供了保证,而这种保证在没有关于数据应该是什么样子的共识的情况下是不可能实现的。这可以帮助你避免数据一致性和连贯性方面的一整类问题,特别是随着与数据库交互的应用程序逻辑的演变,问题会越来越突出。
灵活性的理由
另一方面,文档数据库分别定义每个独立文档的结构。结构是文档本身定义的特性,而不是记录必须符合的_外部_结构。
这在许多不同领域为你提供了极大的灵活性。你可以随时更改要为单个记录记录的数据,延迟或跳过回填以前保存的文档,或者在同一集合中存储结构差异很大的文档,而无需将每个其他文档中缺失的值设置为 NULL。
在开发过程中,你的数据库结构可以轻松地与应用程序逻辑一同演进。这使得更改的负担减轻,因为每次结构更改所需的同步和迁移过程更少。数据库系统将允许你希望应用的任何新文档结构与所有以前的结构并存。如果需要调整现有记录,你可以回填数据或作为单独的过程进行带外结构修改。
文档模型提供的灵活性鼓励了存储逻辑的迭代和演进。然而,重要的是要记住,在你进行更改时,软件本身不太可能为你提供与数据相关的那么多保证。如果对于数据集合所持有的形状没有达成一致的标准,那么作为开发人员,你就需要负责强制执行一致性并在适当情况下修改文档,以使你的数据保持在易于理解的状态。
范式化、连接和数据共存
关系型数据库模型最有用的特性之一是连接(joins)的概念。连接是允许你将不同表中保存的数据缝合在一起,以便将它们作为一个单一单元进行操作的查询。虽然从效率、逻辑或一致性角度来看,将某些数据片段存储在不同的表中可能更合理,但你通常会希望跨这些边界检索数据或执行其他操作。
范式化(Normalization)是一种表设计理念,它鼓励你以一种保证数据在表边界之间一致性的方式组织数据。范式化在某些方面是连接的必要条件,同时也是关系模型中连接之所以必要的主要原因之一。
你可以将范式化视为一种通过根据离散部分的重用程度来逻辑地分离数据,从而维护数据一致性的策略。例如,代表唯一客户的记录与代表客户单个订单之一的记录的使用方式将大相径庭。范式化鼓励你将这些类型的信息分离到各自的表中,而连接则为你提供了在需要时组合它们的所需机制。
连接需要结构一致的数据,并且字段可以相互映射以匹配单个记录。由于文档模型不强制规定记录的固定结构,因此在那种范式下,连接是一种更难实现的操作。话虽如此,重要的是要注意
- 许多文档数据库系统可以实现类似的功能
- 模型本身鼓励更集中的数据存储
这在实践中意味着文档结构没有像关系型数据库那样面临导致范式化的相同压力。记录可以而且通常会包含在关系模型中通常会分离的嵌套信息,这允许你在单个文档中检索相关信息,而不是将多个实体拼接在一起。即便如此,聚合操作符可以使用与关系型数据库相同的一些方法,在文档模型中提供与连接相同的基本功能。
查询数据
关系型数据库传统上倾向于使用结构化查询语言(Structured Query Language),即 SQL,作为其主要的查询语言。SQL 可用于查询现有数据、插入新数据、创建或修改数据库结构以及管理通用数据库环境。SQL 自 20 世纪 70 年代以来一直存在,有许多不同的迭代和实现,通常被认为是遵循基于表结构的数据库的标准接口。
SQL 拥有许多支持者和反对者,可能是一个两极分化的话题,部分原因是其悠久的历史、不一致的标准以及与传统编程语言不同的工效学。SQL 在访问和检索方面相当有表现力和灵活性,但由于其语法和语句结构难以解析和构建,因此在编程处理时可能很繁琐。此外,它不遵循许多其他语言所设定的模式,因为顾名思义,它最初主要被构想为一种命令和查询语言,而不是一种用于数据编程的通用语言。
对于关系型数据库,SQL 通常是与数据库系统交互的主要方式。对于文档数据库,记录结构与 SQL 中固有的假设不符,因此需要新的查询语言来与系统交互以及输入、查询和修改数据。一些语言从 SQL 中汲取了大量灵感,而另一些则实现了全新的语言,试图摆脱 SQL 中一些更令人沮丧的缺陷。
在许多文档数据库中,查询语言被设计为遵循应用程序开发人员可能更熟悉的访问模式。它们通常实现一个类似 API 的接口,模拟开发人员用于类 JSON 数据管理的工具,以便他们可以重用现有模式。虽然关系型数据库倾向于围绕 SQL 标准趋同,但文档数据库和其他 NoSQL 数据库的接口可能彼此差异很大。通常,与实际数据库一起开发的查询语言是不同文档数据库解决方案之间的差异点之一。
超越单个数据库的扩展
大多数传统关系型数据库最初设计于一个假设基础设施环境相当简单的时代。在许多情况下,垂直扩展,即通过向单个主机添加额外资源来扩展数据库性能,是最简单的策略,并且通常可以满足任何新需求。
水平扩展也是可能的,可以通过将数据库复制到多个从库,或者通过分片数据:在多个主机之间拆分数据库,使每个主机负责完整数据的一个子集。这些策略不仅提供了管理单个主机资源的灵活性,还带来了额外的优势,例如提高可用性和缓解故障。
然而,关系型数据库在跨多个主机轻松扩展方面存在限制。对数据一致性的关注意味着写入操作尤其难以在主机之间实现,因为必须有一种方法就数据集应用的更改达成共识。典型的解决方案是将所有写入操作转发到单个主机,或者在多个主机之间协调昂贵的共识算法,这通常会对吞吐量和性能产生重大影响。
较新的关系型数据库已经开发出来以帮助解决这些问题,因此在这一领域取得了显著进展。然而,扩展的某些困难是关系模型本身固有的。当在大部分数据上设置约束和一致性要求时,必须存在一定程度的协调开销来管理各种主机上的状态数据。在某些重要方面,关系模型似乎需要一个集中式管理架构。
另一方面,文档数据库由于其系统中数据的组织方式,能够避免许多这些缺点。通过将相关数据归置在单个文档中,可以最大限度地减少不同主机之间的协调。在文档数据库中,分片数据集是一种更常见的策略。这是因为基于文档的操作通常不需要太多协调,因为许多操作都针对单个记录。
由于文档数据库中单个文档和集合之间存在的约束和链接较少,协调通常更容易,操作也倾向于更自包含。这使得文档数据库提供商能够优先考虑性能和可用性,而关系型数据库通常为了保持一致性而被迫做出让步。这是一种权衡,可能对你的数据安全性以及系统如何处理停机和网络分区产生许多影响。主要区别在于,文档数据库在调整一致性水平与性能和可用性之间往往具有更大的灵活性,而关系型数据库通常要求一致性始终是首要任务。
总结
关系型数据库和文档数据库在组织数据以及使其可管理和可访问方面,在某些方面采用了截然不同的方法。它们的基本设计对它们适合的应用程序类型以及你在使用它们时可能遇到的挑战具有深远的影响。
虽然关系型数据库和文档数据库都可以在某些场景中使用,但你的项目的优先级和开发实践通常与其中一种系统更契合。在可能的情况下,仔细评估这两种选择是值得的,以了解你可能正在做出的权衡,以及哪个系统提供了你真正认为对工作重要的功能。
如果你正在使用Prisma 管理你的 MongoDB 数据库,你需要在 Prisma schema 文件的 'datasource' 块中设置一个连接 URI。你必须为 'url' 字段提供一个连接 URI,以便 Prisma 能够连接到你的数据库。