SQL Server 规范化

规范化的概念是现代OLTP(On-Line Transaction Processing 联机事务处理过程)数据库设计的基石。规范化和关系数据库的概念是同时出现的。两者都来源于E.F.Codd(IBM)在1969年发表的著作。Codd提出这样的概念:数据库是由一系列无序的表组成的,可以对这些表进行非过程操作来返回表。

规范化实际上只是大型数据库设计的一小部分。有时需要规范化数据,有时又需要有意的反规范化数据。即使在规范化过程中,也有很多方式实现技术上所认定的规范化数据库。

规范化

我向Codd发誓,规范化就是键,整个键,只是键。

** 第一范式(1NF)**

第一范式(1NF)全部都是关于消除重复数据组和保证原子性(数据是自包含和独立的)的规范化信息。在较高的层次,这指的是创建主键,然后将任何重复的数据组移动到新的表中,为了这些表创建新键,如此进行下去。

  • 花费:在以前,磁盘存储空间非常昂贵。多次存储数据意味着浪费空间。随着数据存储越来越便宜,这使得重复存储问题不那么显著了。
  • 性能:重复数据意味着更多的数据移动,更多的I/O数量。这意味着影响了性能,因为需要经过数据总线或者网络传输大量的数据。即使现在有更快的传输技术,还是对性能有很大的负面影响。
  • 数据完整性:在行与行之间的重复数据经常出现不一致,产生自相矛盾的数据,而且通常缺乏数据完整性。
  • 分析数据:如果需要查询有组合数据的列的信息,那么必须采用一种方法分析该列的数据(这个操作速度非常慢)。

第二范式(2NF)

规范化的第二步是达到第二范式(2NF)。第二范式进一步减少重复数据的出现(不一定是数据组)。第二范式有以下规则:

  • 表必须符合第一范式的规则(规范化是一个类似堆积木块的过程,如果没有前两块的积木,就不能堆第三块)。
  • 每列必须依赖于整个键。

第三范式(3NF)

第三范式处理的问题是使得表中所有列不仅仅是依赖于某个事物,而是要依赖于正确的事物。第三个范式有以下3个规则:

  • 表必须符合2NF(前面提到过,这个范式类似堆积木)。
  • 任何列都不能依赖于非键列。
  • 不可以有派生的数据。

其他范式

规范化模型中还有其他一些范式(至少在学术界是这么认为的)。它们包括以下范式:

  • Beyce-Codd范式(这实际上是第三范式的变体):这个范式试图解决有多个重叠候选的情况。这只可能在下列条件下发生:
    • 所有候选键是组合键(即键是由多个列组成)。
    • 有多个候选键。
    • 每个候选键至少有一个列和另外一个候选键的列相同。
      这种情况可以有任意多的解决方案,而且几乎从来没有在学术界以外的逻辑上的考虑。
  • 第四范式:这个范式试图解决多值依赖问题。具体情况是:在单个行中,没有列依赖于主键以外的列,而且只依赖于整个主键(符合第三范式)。然而,还有更奇怪的情况:主键中的一列可能分别依赖于主键中的其他列。这种情况非常罕见,通常不会引起实际的问题。因此,他在数据库领域中基本上被忽略了,这里也不讨论这个问题。
  • 第五范式:处理无损和有损分解。实际存在这样的特定的情况:虽然可以分解一个关系,但不能从逻辑上将其重新构成原来的形式,这也是非常罕见的,很大程度上是学术问题,这里不再讨论。

反规范化

规范有时会成为数据库设计者佩戴的十字架,会变成它们的信仰,他们是为了规范化而规范化数据,而不是为了数据库的使用性。下面是对这个问题的一些思考:

  • 如果声明计算列或者存储一些派生数据有助于更有效地运行报表,那么不管怎样也要采用。只需考虑优点和可能的风险(例如,如果“汇总”数据与所派生的数据不同步该怎么办?如何确定不同步的情况,以及如果不同步又该如何处理?)
  • 有时,在表中包括一个(或者多个)反规范化的列。可以消除或者显著减少检索信息所需的连接数量。要注意这些情况,它们会经常出现。我曾处理过这种情况,通过向常用的基表中添加一列,将表连接从9个降低到3个,这个过程中查询时间减少了90%。
  • 如果要保持历史数据(大部分不改动且只用于报表的数据),那么完整性问题是相对次要的考虑事项。一旦数据写到只读区域中并经过验证,那么可以确保不会出现“不同步”的问题(不同步问题是数据规范化主要处理的问题)。这时,将数据以平面形式(反规范化)存储到一些表中则更好(也更快)。
  • 需要连接的表越少,用户制作报表的时候就越开心。这个用户群会越来越熟悉他们使用的工具。用户逐渐变成他们自己的DBA,要直接访问数据库来制作他们自己的自定义报表。对这些用户来说,高度规范化的数据库可能看起来像是迷宫,几乎变得没有用处,反规范化数据可以使这些用户操作起来更容易。
    总而言之,如果有疑问,就规范化数据。通常这样设计关系系统是由原因的。因为越执行规范化,就能获得更好的数据完整性,在事务环境下也会获得更好的性能。

超出规范化的一些规则

规范不同于设计,但将规范作为第一步是很好的做法。

1. 保持简单

一些人确实能想出聪明的办法来解决不同的问题。有的想法特别棒且非常有用。有的想法虽然很好,但是不实用。一些想法往往可能很新颖,但是很难实现。

通常要避免在数据库中引入真正所需的复杂性。最低要求的方法通常(不总是如此)产生的结果不仅更容易编辑,而且运行得更快。

2. 选择数据类型

为了贯彻最低要求的思想,就要选择需要的方法,并且只选择需要的方法。

例如,如果需要存储月份(数字1~12),可以使用单字节数据类型tinyint。那么,为什么经常碰到数据库中存储月份的字段使用int数据类型(这个数据类型是4字节)呢?如果不需要Unicode处理任何数据类型,就不要使用nchar或者nvarchar,和相应的Unicode相比,这些数据类型都需要占用两个字节。

不要随意浪费空间。数据库中出现的很多事情都会重复,这意味着小的错误就会像滚雪球一样变得非常大。

3. 尽量进行存储

每次构建数据时,都会碰到这样一个问题:“以后需要这些信息吗?”我的建议是,如果有疑问,就保存信息。要知道,很多时候无法找回失去的数据。

小结

具体情况具体分析,不能一概而论,不要陷入为了设计而设计的圈套!

参考

《SQLServer2012编程入门经典(第4版)》

    原文作者:银冰雪千载
    原文地址: https://www.jianshu.com/p/ea46cf400c14
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞