简介
数据库相对于其他更简单的数据存储选项的主要优势之一是它们能够以有序、易于查询的结构存储信息。这些功能源于数据库实施模式来描述它们存储的数据。
数据库模式充当数据库中数据形状和格式的蓝图。对于关系数据库,这包括描述数据类别及其通过表、主键、数据类型、索引和其他对象的连接。对于 NoSQL 模式,这通常涉及根据最重要的预期查询模式组织数据。
在任何一种情况下,了解数据库模式的价值以及如何最好地设计和优化它以满足您的需求至关重要。本指南将重点介绍什么是数据库模式、您可能遇到的不同类型的模式、它们为什么重要,以及在设计自己的模式时需要记住什么。
为什么数据库模式如此重要?
数据库模式之所以重要,有很多原因。
您的数据几乎总是包含一些规律性,无论其来源或应用如何。有些数据是高度规则的,这意味着所有数据都可以用相同的模式来描述。有些数据非常不规则,但即便如此,它的元数据,即关于数据本身的情境数据,通常仍然是规则的。
数据库模式告诉数据库您的数据是什么以及如何使用它。数据库模式帮助数据库引擎理解这些模式,这使其能够对数据强制执行约束,在查询时响应正确的信息,并以用户请求的方式操作数据。
好的模式倾向于减少隐式信息,而使其对系统及其用户可见。关系数据库中的模式可以减少信息冗余,确保数据一致性,并提供访问和连接相关数据所需的支架和结构。在非关系上下文中,好的模式通过将存储格式与应用程序必不可少的访问模式对齐,从而实现高性能和可伸缩性。
定义物理模式与逻辑模式
在我们进一步讨论之前,我们应该介绍一些定义。两个可能令人困惑的术语是物理模式和逻辑模式。这两个术语根据它们使用的上下文可能传达不同的含义。
就本文而言,我们主要讨论设计数据库模式时的逻辑模式和物理模式。
在设计数据库模式时
当谈论设计数据库模式时,逻辑模式是将数据组织成不同类别、定义数据属性以及确定数据库项最佳结构的一般设计。此通用文档没有实现细节,因此与平台无关。它可以作为蓝图,并在各种数据库系统中实现。
在相同的上下文中,物理模式被认为是设计过程中的下一步,其中详细制定了特定于实现的细节。不同实体、约束、键、索引和其他项的名称被识别并映射到逻辑模式上。这为使用给定的数据库平台提供了具体的实施计划。
在这种上下文中,逻辑模式和物理模式是设计过程的不同阶段。该过程的目标是通过首先布局数据的抽象质量,然后在稍后将该组织映射到您想要使用的数据库系统的工具集和语言,从而从一组需求中迭代地开发实施计划。
在讨论数据库架构时
有时在数据库方面看到物理模式和逻辑模式的另一个上下文是在实际数据库软件的物理和虚拟架构中。
在这种上下文中,逻辑模式指的是用户与之交互的可见数据库实体。这意味着表、键、视图和索引等对象是用户使用数据库软件创建和操作的抽象概念。这些项在系统中的布局是数据库呈现的逻辑模式的一部分。
在相同的上下文中,物理模式指的是数据库软件在与文件系统交互时处理数据、文件和存储的方式。例如,数据库架构的物理模式可以确定系统是为每个数据库还是每个表存储单独的文件,并确定如何跨多个服务器对这些文件进行分区。
静态模式与动态模式
另一个重要的分类可以帮助澄清关系数据库和非关系数据库中模式之间的差异,是静态模式和动态模式之间的差异。
静态模式是通常与关系数据库关联的模式类型。它们是预先定义的,作为数据必须遵循才能被系统接受的形状的定义。数据库系统在使用静态模式时能够强制执行这些模式,因为静态模式是对数据库系统可以针对其验证输入的期望状态的断言。
相比之下,动态模式在非关系上下文中更为普遍。动态模式不太严格,可能缺乏任何预先设想的组织结构。相反,动态模式出现是基于输入到系统中的数据的质量。虽然许多非关系数据库可以存储具有任意内部结构的信息,但在大多数实际用例中,规则模式往往会出现。
由于动态模式是新兴的结构,因此数据库系统不能将它们用作一致性工具。但是,作为用户,理解和围绕它们进行开发仍然非常重要。了解您的一般数据外观以及您的应用程序将需要如何与之交互将帮助您选择满足您需求、性能良好并避免不必要不一致的结构。
设计数据库模式
现在您已经了解了一些不同类型的数据库模式,那么您如何为您的项目设计一个模式呢?设计有效的模式需要思考和实践,以及对问题领域和将使用数据的系统的透彻理解。
设计过程看起来大相径庭,这取决于您要为其设计模式的数据库类型。具体来说,静态模式的设计过程与动态模式的设计过程不同。实际上,这些最终与为关系数据库(静态)和非关系数据库(动态)设计之间的差异保持一致。
通用技巧
尽管关系数据库和非关系数据库的模式设计之间存在差异,但仍有一些通用技巧适用于任何模式开发。由于其中许多对于设计过程的开始很重要,因此首先讨论这些技巧是有意义的。
了解您的数据
设计模式的第一步始终应该是了解您的数据和领域。如果不了解数据库将管理的信息及其使用的上下文,就不可能开发出好的数据库设计。
虽然您可能在一开始并不了解数据的全部特征,但尽可能多地了解您的系统预期管理的数据对于设计至关重要。
您应该尝试回答的一些问题包括
- 广义上讲,数据将是什么?
- 哪些属性对于记录很重要?
- 您的总数据集有多大?
- 系统累积新数据的速度有多快?
- 您的数据是否高度规则?
了解使用模式
同样,在不了解用户需求的情况下设计数据库模式与在其他软件设计中一样有问题。如果您不是数据将要使用的领域的专家,则需要咨询该领域的专家来指导您了解需求。
您应该问自己这样的问题
- 最常见的查询是否可预测?
- 将有多少并发用户或客户端?
- 典型操作和查询将触及多少数据?
- 大多数请求是读取查询还是写入查询?
- 哪些数据将定期一起查询?
- 大多数操作是针对单个记录还是聚合多个记录?
制定命名约定
虽然它可能看起来不重要,但设计命名约定并严格遵守它将在开发和常规使用期间有所帮助。
命名和样式约定有助于最大限度地减少在命名新实体时需要执行的脑力劳动量。同样,约定允许用户在访问模式中的不同项目时安全地假设一种模式。某些数据库系统或数据库类型已经有流行的命名约定,您可以遵循这些约定以避免意外,并避免需要制定自己的标准。
您可能需要考虑的一些样式和命名约定
- 对于区分大小写的系统,您应该如何使用大写和小写字母?
- 项目何时应使用单词的复数形式,何时应使用单数形式?
- 多字名称是否应使用下划线、破折号或其他分隔符分隔单词?
- 是否应始终使用全名,或者在某些情况下是否允许缩写?
为关系数据库设计模式
关系数据库通常被认为是灵活的通用解决方案。它们处理即席查询的能力允许同一数据库服务于不同的应用程序和用例。因此,在为关系数据库设计模式时,您的最终目标通常是以一种促进灵活性,同时最大限度地减少数据不一致性进入系统的机会的方式来表示您的数据。
开发逻辑模式
关系模式设计通常从逻辑模式开始,如上一节所述。
您绘制出要管理的数据项、它们的关系以及任何重要的属性,而无需考虑实现细节或性能标准。此步骤很重要,因为它在一个地方收集了所有数据项,并允许您在抽象层面上梳理它们彼此关联的方式。
您可以开始草拟表示特定数据项及其属性的表。这种映射过程通常最好用 实体关系(或 ER)模型 来表示。ER 模型是通过定义项目类型及其属性,然后连接这些属性以绘制关系和依赖关系,从而以可视化方式表示数据对象的图表。
ER 模型经常在早期阶段的模式设计中使用,因为它们非常擅长帮助您弄清楚您有哪些不同的实体,必须管理哪些属性,哪些实体彼此相关,以及它们关系的具体性质。使用 ER 模型图来表示您的逻辑模式为您提供了关于您希望数据库设计是什么的可靠计划,而没有评论特定于实现的细节。
开发物理模式
一旦您有了逻辑模式,下一步就是通过创建物理模式(如上一节所述)来弄清楚具体的实现细节。物理模式将准确确定您希望如何使用可用的数据库结构和功能来提交您的计划。
第一步通常是遍历每个数据库实体并确定您的主键字段。主键用于唯一标识表中的每个记录,以及将来自不同表的记录绑定在一起。当逻辑模式中的两个实体之间存在关系时,您将必须通过在一个表中引用主键作为另一个表中的外键来连接物理模式中的两个表。这种关系的方向将影响您在使用数据库时可以多快、多容易地将不同实体连接在一起的性能和便利性。
您在此阶段要考虑的另一个因素是预测的查询模式。某些表以及这些表中的字段将被比其他表和字段更频繁地访问。这些“热点”是数据库索引的良好候选者。数据库索引显着加快了常用项目的检索速度,但代价是在数据更新期间性能较差。确定最初索引哪些列将帮助您平衡这些担忧,并定义系统中索引最关键的位置。
规范化您的数据结构
在此过程中,您可能会发现将某些元素从逻辑实体提取到它们自己的独立表中更容易。例如,您可能希望从客户中提取送货地址,以便可以将多个送货地址与单个客户关联,并且产品订单可以引用特定地址。这些更改可以被认为是称为规范化的过程的一部分。
数据库规范化是一个过程,可确保您的数据库只表示每条数据一次,并且不允许导致不一致的更新。规范化是一个庞大的主题,在很大程度上超出了本指南的范围,但是您物理模式设计过程的一部分涉及弄清楚要寻求的规范化级别,并根据需要转换数据实体以实现该目标。
为非关系数据库和 NoSQL 数据库设计模式
非关系数据库的设计过程通常看起来大相径庭。这种差异的很大一部分源于这样一个事实,即通常选择非关系数据库是为了在有限数量的预定义查询上实现高性能。
确定您的主要查询
非关系数据库模式通常与将使用它们的应用程序一起设计。该模式反映了应用程序的特定需求,并且在某种意义上,是一种为适应应用程序开发的模型而设计的自定义结构。
由于这种密切的关系,确定您的数据库必须优化响应哪些查询非常重要。第一步是弄清楚您的数据库需要运行哪些查询。由于您还没有数据结构,这些将是伪查询,但了解您的应用程序需要哪些数据来执行某些操作是您的首要目标。
一旦您对您的应用程序将需要执行哪些查询有了一个很好的了解,您就需要选择最重要的查询来关注。这些是您的应用程序经常执行并且无法承受等待的查询。
定义哪些查询最重要会告诉您数据结构需要围绕哪些确切的访问模式进行优化。数据库系统存储和表示数据的方式将对其快速检索和操作数据项的能力产生巨大影响。
围绕您的主要查询设计您的初始模式
现在您已经了解了最重要的访问模式,您可以开始开发与这些查询匹配的模式。
此过程的第一步是确定每个查询需要返回的确切信息。然后,绘制出将响应查询的所有信息存储在单个实体中的外观。
例如,如果您的应用程序将查询您的数据库以检索用户个人资料信息,那么您的起点很可能是假设所有用户个人资料信息都可以存储在一个地方。
在可能的情况下合并和去重数据实体
在您确定了所需的属性并绘制出将与每个查询相关的所有项目存储在单个实体中的外观之后,请检查是否存在重叠。其想法是在可能的情况下合并数据实体,以减少系统将维护的单独项目数量。您维护的不同实体类型越多,出现不一致和更新性能问题的机会就越大。
其中一些重叠将相当明显。一个查询返回另一个查询的属性子集的情况可以安全地折叠为一个实体。
其他时候,可能更难确定如何映射查询的信息。非关系数据库通常不擅长在单个查询中合并来自多个实体的数据,而关系数据库通过连接在这方面表现出色。因此,当某些属性或实体出现在多个查询中时,您可能必须选择如何最好地表示该数据。
确定您的应用程序可以在哪里填补空白
对于某些查询,您的应用程序可能需要完成一部分数据组装工作,而不是依赖数据库在单个查询中响应所有相关信息。例如,如果您需要处理客户信息及其关联的订单,则将订单存储在不同的类别中,并在您的客户对象中通过 ID 引用它们可能是有意义的。
某些数据库系统无法通过跟踪对象之间的引用来轻松连接此信息。相反,您的应用程序可能需要首先查询客户,然后使用您发现的订单 ID 为每个相关订单发出额外的查询。
在您的应用程序代码中执行这些操作可以帮助解决某些非关系数据库的限制。这通常比尝试在单个条目中维护大量信息或尝试为许多不同类型的数据库对象多次复制数据更好。这些选项可能导致非常糟糕的性能和数据一致性。
话虽如此,一旦您的应用程序代码和数据库模式都上线,测试和调整它们以确保您没有用良好的应用程序性能换取快速的数据库操作将非常重要。一个好的经验法则是尽可能使用数据库的功能,因为它们针对信息检索和操作进行了高度优化,并在需要时在您的应用程序中进行补充。
确定适当的分区键
对于高度可扩展的非关系型数据库,用户通常需要确定分区键或分片键。 这些键将用于在各种服务器之间拆分数据集,以提高性能和响应速度。
找到合适的分区键在很大程度上取决于您的数据和工作负载。 然而,一些通用规则可以为您提供指导。
最好尝试选择一个键分布相当均匀的分区键。 例如,如果您需要分发客户数据,则他们的出生月份通常会带来不错的分布。 相比之下,如果您销售冬季服装,注册月份将不是一个好的分区键,因为您产品的季节性可能会影响键的分布。 对您的候选数据应用哈希算法有时也有助于更均匀地分布您的键空间。
另一个需要考虑的因素是您的工作负载是读密集型还是写密集型。 如果您有一个读密集型应用程序,您可能希望选择一个分区键,该分区键允许您尽可能多地将相关数据写入单个服务器。 这将帮助您避免每次需要检索相关数据时都必须从多个服务器读取数据。
另一方面,如果您有写密集型工作负载,通常最好将写入操作分散到尽可能多的服务器上。 如果每个请求最终都将数据写入同一服务器,那么对于写密集型操作,您将无法获得太多性能提升。
总结
设计有效的数据库模式需要耐心、实践,并且通常需要大量的试验和错误。
首先,您必须尝试对您的数据外观、应用程序将如何使用数据以及需要哪些可用性和数据完整性要求有一个好的了解。 之后,您的目标是开发一个反映您数据的特定特征并促进您预期的用例的模式。
模式设计,就像任何其他类型的设计一样,是一个迭代过程。 当您对问题空间的理解加深以及获得真实世界的性能数据时,预计会更改您的设计。 虽然您可能需要随着时间的推移发展您的模式,但从坚实的基础开始将有助于您完成此过程,并降低未来发生剧烈的、破坏性的模式更改的可能性。
Prisma 在 数据模型 部分的 Prisma 模式 文件中定义了其数据的特征。 查看链接的文档以了解有关这些概念如何应用于 Prisma 的更多信息。
您可能还想查看 Prisma 模式 API 参考页面,以了解如何使用各种功能。