规范化
数据库的逻辑设计(包括各种表和表间关系)是优化关系数据库的核心。设计好逻辑数据库,可以为优化数据库和应用程序性能打下基础。逻辑数据库设计不好,会影响整个系统的性能。
规范化逻辑数据库设计包括使用正规的方法来将数据分为多个相关的表。有几个具有较少列的窄表是规范化数据库的特征。有少量具有较多列的宽表是非规范化数据库的特征。
通常,合理的规范化会提高性能。如果包含有用的索引,SQL Server 查询优化器可有效地在表间选择快速、有效的联接。
下面给出了规范化的一些好处:
- 使排序和创建索引更加迅速。
- 聚集索引的数目更大。有关详细信息,请参阅聚集索引设计指南。
- 索引更窄、更紧凑。
- 每个表的索引更少。这可提高 INSERT、UPDATE 和 DELETE 语句的性能。
- 空值更少,出现不一致的机会更少。这可增加数据库的紧凑性。
随着规范化的不断提高,检索数据所需的联接数和复杂性也将不断增加。太多表间的关系联接太多、太复杂可能会影响性能。合理的规范化通常很少包括经常性执行且所用联接涉及 4 个以上表的查询。
有 时,逻辑数据库设计已经固定,全部进行重新设计是不现实的。但是,尽管如此,将大表有选择性地进行规范化处理,分为几个更小的表是可能的。如果是通过存储 过程对数据库进行访问,则在不影响应用程序的情况下架构可能发生更改。如果不是这种情况,那么可以创建一个视图,以便从应用程序隐藏架构的更改。
![](http://i.technet.microsoft.com/Platform/Controls/CollapsibleArea/resources/minus.gif)
在关系数据库设计理论中,规范化规则指出了在设计良好的数据库中必须出现或不出现的某些属性。关于规范化规则的完整讨论不属于本主题的范畴。不过,有几个可帮助获得合理的数据库设计的规则:
- 表应该有一个标识符。
数据库设计理论的基本原理是:每个表都应有一个唯一的行标识符,可以使用列或列集将任何单个记录同表中的所有其他记录区别开来。每个表都应有一个 ID 列,任何两个记录都不能共享同一 ID 值。作为表的唯一行标识符的列是表的主键。在 AdventureWorks 数据库中,每个表有一个标识列作为主键列。例如,VendorID 是 Purchasing.Vendor 表的主键。 - 表应只存储单一类型实体的数据。
试图在表中存储过多的信息会影响对表中的数据进行有效、可靠的管理。在 AdventureWorks 示例数据库中,销售订单和客户信息存储在不同的表中。虽然可在单独的表中创建包含有关销售订单和客户信息的列,但是此设计会导致出现几个问题。必须在每个 销售订单中另外添加和存储客户信息、客户姓名和地址。这将使用数据库中的其他存储空间。如果客户地址发生变化,必须更改每个销售订单。另外,如果从 Sales.SalesOrderHeader 表中删除了客户最近的销售订单,该客户的信息将会丢失。 - 表应避免可为空的列。
表中的列可定义为允许空值。空值表示没有值。虽然在个别情况下,允许空值可能是有用的,但是应尽量少用。这是因为需要对它们进行特殊处理,从而会增加数据 操作的复杂性。如果某一表中有几个可为空值的列,并且列中有几行包含空值,则应考虑将这些列置于链接到主表的另一表中。通过将数据存储在两个不同的表中, 主表的设计会非常简单,而且仍能够满足存储此信息的临时需要。 - 表不应有重复的值或列。
数据库中某一项目的表不应包含有关特定信息的一些值。例如,AdventureWorks 数据库中的某产品可能是从多个供应商处购买的。如果 Production.Product 表有一列为供应商的名称,这就会产生问题。一个解决方案是将所有供应商的名称存储在该列中。但是,这使得列出各个供应商变得非常困难。另一个解决方案是更 改表的结构来为另一个供应商的名称再添加一列。但是,这只允许有两个供应商。此外,如果一本书有三个供应商,则必须再添加一列。
如果您发现需要在单个列中存储多个值,或者一类数据(例如 TelephoneNumber1 和 TelephoneNumber2)对应于多列,则应考虑将重复的数据置于链接回主表的另一个表中。AdventureWorks 数据库有一个用于存储产品信息的 Production.Product 表和一个用于存储供应商信息的 Purchasing.Vendor 表,还有第三个表 Purchasing.ProductVendor。第三个表只存储产品的 ID 值和产品供应商的 ID 值。这种设计允许产品有任意多个供应商,而无需修改表的定义,也无需为单个供应商的产品分配未使用的存储空间。