关系型数据库管理系统 (RDBMS)


关系数据库设计 (RDD) 模型将信息和数据组织成一组包含行和列的表。关系/表的每一行表示一条记录,每一列表示数据的某个属性。结构化查询语言 (SQL) 用于操作关系数据库。关系数据库的设计由四个阶段组成,其中数据被建模成一组相关的表。这些阶段是 -

  • 定义关系/属性
  • 定义主键
  • 定义关系
  • 规范化

关系数据库在组织数据和执行事务方面的方法与其他数据库不同。在 RDD 中,数据被组织成表,所有类型的数据访问都通过受控事务进行。关系数据库设计满足数据库设计所需的 ACID(原子性、一致性、完整性和持久性)属性。关系数据库设计要求在应用程序中使用数据库服务器来处理数据管理问题。

 

关系数据库设计过程

数据库设计更像是一门艺术而不是科学,因为您必须做出许多决策。数据库通常是根据特定应用程序定制的。没有两个定制的应用程序是相同的,因此,没有两个数据库是相同的。在做出这些设计决策时,会提供一些指导原则(通常是关于不做什么而不是做什么),但最终的选择取决于设计人员。

步骤 1 - 定义数据库的目的(需求分析)

  • 收集需求并定义数据库的目标。
  • 草拟示例输入表单、查询和报表通常会有所帮助。

步骤 2 - 收集数据、组织成表并指定主键

  • 确定数据库的目的后,收集需要存储在数据库中的数据。将数据划分为基于主题的表。
  • 选择一列(或几列)作为所谓的主键,它唯一地标识每一行。

步骤 3 - 在表之间创建关系

一个由独立且不相关的表组成的数据库几乎没有用处(您可以考虑改用电子表格)。关系数据库的强大功能在于可以在表之间定义关系。设计关系数据库最关键的方面是识别表之间的关系。关系类型包括

  • 一对多
  • 多对多
  • 一对一

一对多

在“课程花名册”数据库中,一名教师可以教授零个或多个课程,而一个课程由一位(且仅一位)教师教授。在“公司”数据库中,一名经理可以管理零个或多个员工,而一名员工由一位(且仅一位)经理管理。在“产品销售”数据库中,一名客户可以下多个订单;而一个订单由一个特定的客户下达。这种关系称为一对多。

一对多关系不能在一个表中表示。例如,在“课程花名册”数据库中,我们可以从一个名为 Teachers 的表开始,该表存储有关教师的信息(例如姓名、办公室、电话和电子邮件)。为了存储每位教师教授的课程,我们可以创建列 class1、class2、class3,但立即面临创建多少列的问题。另一方面,如果我们从一个名为 Classes 的表开始,该表存储有关课程的信息,我们可以创建其他列来存储有关(一个)教师的信息(例如姓名、办公室、电话和电子邮件)。但是,由于一名教师可以教授许多课程,因此其数据将在 Classes 表的许多行中重复。

为了支持一对多关系,我们需要设计两个表:例如,一个名为 Classes 的表来存储有关课程的信息,其中 classID 作为主键;以及一个名为 Teachers 的表来存储有关教师的信息,其中 teacherID 作为主键。然后,我们可以通过将 Teacher 表(即 teacherID)(“一”端或父表)的主键存储在 Classes 表(“多”端或子表)中来创建一对多关系,如下所示。

  子表 Classes 中的列 teacherID 被称为外键。子表的外键是父表的主键,用于引用父表。

多对多

在“产品销售”数据库中,客户的订单可能包含一个或多个产品;并且一个产品可以出现在多个订单中。在“书店”数据库中,一本书由一个或多个作者撰写;而一位作者可以撰写零个或多个书籍。这种关系称为多对多。

让我们以“产品销售”数据库为例。我们从两个表开始:Products 和 Orders。Products 表包含有关产品的信息(例如名称、描述和库存数量),其中 productID 作为其主键。Orders 表包含客户的订单(customerID、dateOrdered、dateRequired 和状态)。同样,我们不能在 Orders 表中存储订购的商品,因为我们不知道为商品保留多少列。我们也不能在 Products 表中存储订单信息。

为了支持多对多关系,我们需要创建一个第三个表(称为连接表),例如 OrderDetails(或 OrderLines),其中每一行表示特定订单的商品。对于 OrderDetails 表,主键包含两列:orderID 和 productID,它们唯一地标识每一行。OrderDetails 表中的列 orderID 和 productID 用于引用 Orders 和 Products 表,因此,它们也是 OrderDetails 表中的外键。

 

实际上,多对多关系是通过引入连接表实现为两个一对多关系。

 一个订单在 OrderDetails 中有多个商品。OrderDetails 商品属于一个特定的订单。

 一个产品可能出现在多个 OrderDetails 中。每个 OrderDetails 商品指定了一个产品。

一对一

在“产品销售”数据库中,一个产品可能有一些可选的补充信息,例如图像、更多描述和评论。将它们保存在 Products 表中会导致许多空闲空间(在没有这些可选数据的记录中)。此外,这些大型数据可能会降低数据库的性能。

相反,我们可以创建另一个表(例如 ProductDetails、ProductLines 或 ProductExtras)来存储可选数据。只有在那些具有可选数据的产品中才会创建记录。这两个表 Products 和 ProductDetails 表现出一对一的关系。也就是说,对于父表中的每一行,子表中最多只有一行(可能为零)。相同的列 productID 应同时用作两个表的主键。

一些数据库限制了可以在表中创建的列数。您可以使用一对一关系将数据拆分为两个表。一对一关系也可用于将某些敏感数据存储在安全表中,而非敏感数据存储在主表中。

列数据类型

您需要为每一列选择合适的数据类型。常见的数据类型包括整数、浮点数、字符串(或文本)、日期/时间、二进制、集合(如枚举和集合)。

步骤 4 - 优化和规范化设计

 例如,

  •  添加更多列,
  • 使用一对一关系为可选数据创建新表,
  • 将一个大表拆分为两个较小的表,
  • 其他方法。

规范化

应用所谓的规范化规则来检查您的数据库在结构上是否正确且最优。

**第一范式 (1NF):**如果每个单元格包含单个值而不是值列表,则表为 1NF。此属性称为原子性。1NF 还禁止重复的列组,例如 item1、item2、itemN。相反,您应该使用一对多关系创建另一个表。

**第二范式 (2NF) -** 如果表为 1NF 并且每个非键列都完全依赖于主键,则该表为 2NF。此外,如果主键由多列组成,则每个非键列应依赖于整个集合,而不是其一部分。

例如,OrderDetails 表的主键包含 orderID 和 productID。如果 unitPrice 仅依赖于 productID,则不应将其保留在 OrderDetails 表中(而应保留在 Products 表中)。另一方面,如果单价依赖于产品以及特定订单,则应将其保留在 OrderDetails 表中。

**第三范式 (3NF) -** 如果表为 2NF 并且非键列彼此独立,则该表为 3NF。换句话说,非键列仅依赖于主键,仅依赖于主键,以及其他任何内容。例如,假设我们有一个 Products 表,其中包含列 productID(主键)、名称和 unitPrice。如果 discountRate 也依赖于 unitPrice(它不是主键的一部分),则 discountRate 不应属于 Products 表。

**更高范式:**3NF 有其不足之处,这导致了更高的范式,例如 Boyce/Codd 范式、第四范式 (4NF) 和第五范式 (5NF),这超出了本教程的范围。

 有时,出于性能原因,您可能会决定违反某些规范化规则(例如,在 Orders 表中创建名为 totalPrice 的列,该列可以从 orderDetails 记录中派生);或者因为最终用户要求这样做。确保您充分了解这一点,开发处理它的编程逻辑,并正确记录此决策。

完整性规则

您还应应用完整性规则来检查设计的完整性 -

  **1. 实体完整性规则 -** 主键不能包含 NULL。否则,它无法唯一标识该行。对于由多列组成的复合键,任何列都不能包含 NULL。大多数 RDBMS 检查并强制执行此规则。

   **2. 参照完整性规则 -** 每个外键值必须与引用的表(或父表)中的主键值匹配。

只有当父表中存在该值时,您才能在子表中插入带有外键的行。

如果父表中的键值发生变化(例如,行更新或删除),则子表中所有具有此外键的行都必须相应地处理。您可以选择:(a)不允许更改;(b)级联更改(或删除记录)以相应地更新子表;(c)将子表中的键值设置为 NULL。

大多数关系数据库管理系统 (RDBMS) 可以被设置为以指定的方式执行检查并确保引用完整性。

    3.业务逻辑完整性 - 除了以上两个一般完整性规则之外,还可能存在与业务逻辑相关的完整性(验证),例如,邮政编码应为特定范围内的 5 位数字,送货日期和时间应在营业时间内;订购数量应等于或小于库存数量等。这些可以通过针对特定列的验证规则或编程逻辑来执行。

列索引

您可以在选定的列上创建索引以方便数据搜索和检索。索引是一个结构化文件,可以加快 SELECT 数据访问的速度,但可能会减慢 INSERT、UPDATE 和 DELETE 的速度。如果没有索引结构,要处理带有匹配条件的 SELECT 查询(例如,SELECT * FROM Customers WHERE name='Tan Ah Teck'),数据库引擎需要比较表中的每条记录。一个专门的索引(例如,BTREE 结构)可以在不比较每条记录的情况下找到记录。但是,每当记录发生更改时,都需要重建索引,这会导致与使用索引相关的开销。

索引可以定义在单个列上、一组列上(称为连接索引)或列的一部分上(例如,VARCHAR(100) 的前 10 个字符)(称为部分索引)。您可以在一个表中构建多个索引。例如,如果您经常使用客户姓名或电话号码搜索客户,则可以通过在 customerName 列以及 phoneNumber 列上构建索引来加快搜索速度。大多数 RDBMS 会自动在主键上构建索引。

 

更新于: 2024年5月4日

17K+ 浏览量

启动您的 职业生涯

通过完成课程获得认证

开始
广告