10

我是个jr。开发人员(工作 5 个月),我有一个关于数据规范化的问题。现在,据我了解,数据规范化背后的一般原则是创建一个 RDBMS,将​​数据冗余保持在最低限度。在我的项目中,其中一位 DB 人员创建了一个 DB。我们有 50 多个表,数据库中的表通常非常零散,即。一张表有两三列,就是这样。现在,当涉及到编写 sql 查询时,它已成为一个小麻烦,因为每个查询都涉及梳理几个不同的表并将它们连接在一起。我想知道这是否是数据规范化的副作用?或者这是否指向别的东西?

我知道对我来说最简单的事情就是根据我必须编写的查询来编写表。这将创建一个包含大量冗余数据的数据库,但我很好奇是否有一个快乐的媒介?

就像附言一样,我不想让人觉得我在抱怨我的工作,但我真的很想了解更多关于这个的信息。我的工作环境不是最友好的,所以我不愿意和同事提出这个问题。但是,如果有经验丰富的人提供任何想法、书籍、教程或意见,我将不胜感激。

谢谢。

4

7 回答 7

4

数据规范化背后的一般原则是创建一个 RDBMS,其中数据冗余保持在最低限度。

只是部分正确。

规范化与“冗余”无关。

这是关于“更新异常”的。

1NF 是“不要使用数组”规则。打破 1NF 意味着一行不是原子的,但是集合和集合中的独立更新不会很好地工作。会有锁定和缓慢。

2NF是“一键”规则。每行只有一个键,行中的所有内容都取决于该键。密钥的一部分没有依赖关系。有些人喜欢谈论候选键、自然键和外键;它们可能存在,也可能不存在。当所有属性都依赖于一个键时,满足 2NF。如果键是单列代理键,那么这个范式很容易满足。

如果违反了 2NF,则您的列依赖于键的一部分,而不是整个键。如果您有一个以(零件号,修订号)为键的表格,以及颜色和重量的属性,其中重量取决于整个键,但颜色仅取决于零件号。您有一个 2NF 问题,您可以更新某些零件颜色但不能更新其他颜色,从而产生数据异常。

3NF 是“唯一关键”规则。如果将派生数据放在一行中,并更改派生结果,它与源列不匹配。如果您更改源列而不更新派生值,您也会遇到问题。是的,触发器是允许违反 3NF 设计的一个坏方法。那不是重点。重点只是定义 3NF 并表明它可以防止更新问题。

每个查询都涉及梳理几个不同的表并将它们连接在一起。我想知道这是否是数据规范化的副作用?

这是。

于 2011-06-22T00:52:23.543 回答
3

现在,据我了解,数据规范化背后的一般原则是创建一个 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

两个依赖关系表明该表具有传递依赖关系。

  1. Winner_date_of_birth 中的值似乎在功能上取决于主键。每个主键值确定了一个且只有一个值作为 Winner_date_of_birth。但 。. .
  2. Winner_date_of_birth 中的值在功能上似乎也取决于获胜者。获胜者的每个值决定了一个且只有一个获胜者日期的值。

鉴于这两个明显的功能依赖关系以及对锦标赛获胜者出生日期这两个词的含义的理解,我们可以说

  • 获胜者->获胜者日期的出生是一个功能依赖,并且
  • {tournament, year} -> 获胜者是一个函数依赖,并且
  • {tournament, year} -> Winner_date_of_birth 是一个传递依赖。
于 2011-06-24T23:15:57.720 回答
2

在这种困境中,数据库视图是一个至关重要的工具。 这个出色的介绍说:

好消息是:您不必使用规范化表!...在规范化数据表之上创建连接视图的抽象层非常容易(至少对于 DBA 而言),将基表完全“置于幕后”,并且不可见。

于 2011-06-22T03:09:30.070 回答
1

这听起来像是数据规范化,但我必须更多地了解架构、业务案例等,才能可靠地进行调用。如果您可以控制数据库,则可以编写一个表示链接表的常见查询的视图。为了提高性能,您可以创建索引或物化视图(名称取决于数据库平台,在本例中为 Oracle 与 Sql Server)。

几乎任何数据库入门都会帮助您了解这些概念。如果您正在使用 Sql Server 并且真的有兴趣了解更多信息,SQL Server 联机丛书是一个很好的资源。

于 2011-06-22T00:50:53.933 回答
0

在一个设计良好的数据库中,您在查询中需要的连接应该很容易编写代码。缺点是你有冗长的 SQL。好处是巨大的:-

  • 一致的易于更新的表。
  • 根据业务需求快速更改。设计良好的数据库通常可以处理在原始设计中甚至没有考虑过的查询。
  • 快速适应新实体。将新的数据实体和属性添加到设计良好的数据库中相对容易。对非规范化数据库进行看似简单的更改可能是一场噩梦。
于 2011-06-22T03:40:03.747 回答
0

拥有大量表绝对是规范化数据库设计的标志。这在编写查询时可能会很痛苦,但比让数据不同步要好得多。

我有时会编写从包含数千个表的数据库运行的报告。每天晚上,我们都有一个程序运行并将生产表中的数据转储到数据仓库中,以便我们可以更轻松地对其进行报告。数据仓库表的规范化程度要低得多,这使得编写查询更加简单。如果在您的情况下有意义,您可能需要考虑这样的事情。

于 2011-06-22T00:48:43.873 回答
0

在没有看到数据的情况下,很难说您的数据是否过度规范化(或者只是没有正确规范化 - 将字段分布在多个表中并不意味着它已规范化)一般来说,您可能需要连接多个表才能查看标准化数据库中的有用数据。

您可以创建将表连接在一起的视图,然后您可以查询该视图。这在选择数据时可能会有所帮助。

于 2011-06-22T00:51:27.287 回答