现在,据我了解,数据规范化背后的一般原则是创建一个 RDBMS,将数据冗余保持在最低限度。
嗯,好的。
在我的项目中,其中一位 DB 人员创建了一个 DB。我们有 50 多个表,数据库中的表通常非常零散,即。一张表有两三列,就是这样。
桌子的数量并不能说明设计的好坏。有些企业需要一两个。其他人需要更多。我曾在财富 500 强的数据库中工作过,其中包含数千个表。
列的数量并不能说明设计的好坏。并且列数与碎片无关。我会说列相对较少的表通常是一个好兆头。并不总是一个好兆头,但通常是一个好兆头。
现在,当涉及到编写 sql 查询时,它已成为一个小麻烦,因为每个查询都涉及梳理几个不同的表并将它们连接在一起。我想知道这是否是数据规范化的副作用?或者这是否指向别的东西?
这有两个不同的常见原因。
当您对表进行规范化时,您可以通过识别功能依赖关系、隔离一个或多个新表中的功能依赖列并将它们从原始表中删除来减少冗余(并提高数据完整性)。因此,在从较低范式到较高范式的意义上,对表格进行规范化
- 总是增加桌子的数量,
- 总是减少原始表中的列数,并且
- 有时需要连接才能为人类检索数据。
另一种常见的做法是用 id 号替换字符串。这与标准化无关。(没有“id number normal form”之类的东西。)用 id 号替换字符串
- 总是增加桌子的数量,
- 不会更改原始表中的列数(除非与规范化同时进行),
- 总是需要一个连接来为人类检索数据。
该线程的其他部分似乎有些混乱。我意识到,严格来说,以下内容均与 OP 的问题没有直接关系。
1NF是“一值”原则。它与“原子”行没有任何关系。在关系模型中,原子不是指行。它指的是价值观。
“一个值”意味着行和列的每个交集都包含一个值。(换句话说,值是“原子的”。但是原子这个词有一些不幸的含义,所以大多数现代从业者都避免使用它。)这个值不需要简单;它可以任意复杂。但是,如果它有自己有意义的部分,dbms 要么完全忽略这些部分,要么提供操作它们的函数。(您不必编写函数来操作这些部分。)
我认为最简单的例子是约会。日期有部分,由年、月和日组成。dbms 要么忽略这些部分(如中SELECT CURRENT_DATE
),要么提供操作它们的函数(如中SELECT EXTRACT(YEAR FROM CURRENT_DATE)
)。
试图回避“一个值”原则会导致一个推论:“无重复组”原则。
重复组包含来自一个域的多个值,所有值具有相同的含义。所以像下面这样的表是一种重复组的例子。(还有其他类型。)“phone_1”和“phone_2”的值来自同一个域,并且它们具有相同的含义——用户“n”有电话号码(phone_1 和phone_2)。(主键是“user_id”。)
user_id phone_1 phone_2
1 (111) 222-3333 (111) 222-3334
2 (111) 222-3335 (111) 222-3336
但是下一张桌子虽然很相似,但没有重复组。这些值来自同一个域,但它们的含义不同。(主键是“user_id”。)
user_id home_phone work_phone
3 (111) 222-3333 (111) 222-3334
4 (111) 222-3335 (111) 222-3336
2NF是“全键”原则。它与键的数量无关;具有“n”列的表可能有“n”个键。(例如,请参阅this other SO answer。)在关系模型中(以及,当您进行规范化练习时),如果您单独看到单词键,请考虑“候选键”。
相反,2NF 与具有多列的候选键有关。当一个候选键有多个列时,2NF 要求每个非主属性在功能上依赖于每个候选键的所有列,而不仅仅是任何候选键的某些列。(非主属性是不属于任何候选键的属性。)
以下示例改编自2nf 上的 Wikipedia 条目。(主键是 {employee, Skill}。)
Table: employee_skills
employee skill current_work_location
--
Jones Typing 114 Main Street
Jones Shorthand 114 Main Street
Jones Whittling 114 Main Street
Bravo Light Cleaning 73 Industrial Way
Ellis Alchemy 73 Industrial Way
Ellis Flying 73 Industrial Way
Harrison Light Cleaning 73 Industrial Way
虽然非主列 current_work_location 在功能上依赖于主键 {employee, Skill},但它在功能上也仅依赖于主键的一部分,即“员工”。该表不在 2NF 中。
您不能通过为每一行分配一个代理键来回避 2NF 问题。(主键是 es_id;前一个主键 {employee, Skill} 有一个 UNIQUE 约束)。
Table: employee_skills
es_id employee skill current_work_location
--
1 Jones Typing 114 Main Street
2 Jones Shorthand 114 Main Street
3 Jones Whittling 114 Main Street
4 Bravo Light Cleaning 73 Industrial Way
5 Ellis Alchemy 73 Industrial Way
6 Ellis Flying 73 Industrial Way
7 Harrison Light Cleaning 73 Industrial Way
很明显,添加 id 号并没有消除部分依赖employee->current_work_location
。在不去除部分依赖的情况下,该表仍然不在 2NF 中。
3NF 是“无传递依赖”原则。它不一定与派生或计算的数据有任何关系,正如您可以从Wikipedia example中看出的那样,在此处改编。(主键是 {tournament, year}。此表不在 3NF 中。)
Table: tournament_winners
tournament year winner winner_date_of_birth
--
Indiana Invitational 1998 Al Fredrickson 21 July 1975
Cleveland Open 1999 Bob Albertson 28 September 1968
Des Moines Masters 1999 Al Fredrickson 21 July 1975
Indiana Invitational 1999 Chip Masterson 14 March 1977
两个依赖关系表明该表具有传递依赖关系。
- Winner_date_of_birth 中的值似乎在功能上取决于主键。每个主键值确定了一个且只有一个值作为 Winner_date_of_birth。但 。. .
- Winner_date_of_birth 中的值在功能上似乎也取决于获胜者。获胜者的每个值决定了一个且只有一个获胜者日期的值。
鉴于这两个明显的功能依赖关系以及对锦标赛、获胜者和出生日期这两个词的含义的理解,我们可以说
- 获胜者->获胜者日期的出生是一个功能依赖,并且
- {tournament, year} -> 获胜者是一个函数依赖,并且
- {tournament, year} -> Winner_date_of_birth 是一个传递依赖。