21

我有这些表:

Projects(projectID, CreatedByID)
Employees(empID,depID)
Departments(depID,OfficeID)
Offices(officeID)

CreatedByID是 的外Employees我有一个几乎在每次页面加载时都会运行的查询。

OfficeID只添加一个冗余列Projects来消除三个连接是不好的做法吗?或者我应该执行以下操作:

SELECT * 
FROM Projects P
JOIN Employees E   ON P.CreatedBY = E.EmpID
JOIN Departments D ON E.DepID = D.DepID
JOIN Offices O     ON D.officeID = O.officeID
WHERE O.officeID = @SomeOfficeID

在应用程序编程中,我“先编写最佳实践,然后再优化”,但数据库管理员总是警告连接成本。

4

13 回答 13

36

规范化直到它受伤,然后去规范化直到它工作

于 2009-01-30T18:09:58.243 回答
31

SELECT非规范化在大型查询上具有fast s的优势。

缺点是:

  • 确保完整性需要更多的编码和时间(这在您的情况下最重要)

  • DML(插入/更新/删除)速度较慢

  • 它需要更多空间

至于优化,您可以针对更快的查询或更快的 DML 进行优化(通常,这两者是对立的)。

为更快的查询进行优化通常意味着复制数据,无论是非规范化、索引还是额外的表。

在索引的情况下,RDBMS会为您完成,但在非规范化的情况下,您需要自己编写代码。如果Department搬到另一个地方Office怎么办?您需要在三个表而不是一个表中修复它。

因此,正如我从您的表格名称中看到的那样,那里不会有数百万条记录。所以你最好规范化你的数据,这样管理起来会更简单。

于 2009-01-30T18:07:28.873 回答
10

始终尽可能规范化以消除数据库完整性问题(即潜在的重复或丢失数据)。

即使非规范化带来了性能提升(通常情况并非如此),失去数据完整性的代价也太高了,无法证明是合理的。

只需询问任何必须努力解决遗留数据库中所有晦涩问题的人,他们是否更喜欢良好的数据或微不足道的(如果有的话)速度提升。

此外,正如约翰所提到的 - 如果您最终需要非规范化数据(用于速度/报告/等),则在单独的表中创建它,保留原始数据。

于 2009-01-30T18:15:12.447 回答
7

加入的成本本身不应该让你太担心(除非你试图扩展到数百万用户,在这种情况下你绝对应该担心)。

我会更担心对调用它的代码的影响。规范化的数据库更容易编程,并且几乎总是可以提高应用程序本身的效率。

也就是说,不要超出理性的范围进行规范化。我已经看到为了规范化而进行的规范化,它通常最终出现在一个数据库中,该数据库有一个或两个实际数据表,以及 20 个只填充外键的表。这显然是矫枉过正。我通常使用的规则是:如果列中的数据会重复,则应该对其进行规范化。

于 2009-01-30T18:04:46.837 回答
5

最好将该模式保留在第三范式中,让您的 DBA 抱怨连接成本。

于 2009-01-30T19:54:02.357 回答
4

如果您的数据库一开始没有正确规范化,则 DBA 应该关注。在您仔细测量性能并确定您有瓶颈之后,您可能会开始反规范化,但我会非常谨慎。

于 2009-01-30T18:05:45.040 回答
4

我最关心的是那些警告你加入成本的 DBA,除非你处于高度病态的情况。

于 2009-01-30T20:04:29.403 回答
4

在尝试其他所有方法之前,您不应该查看非规范化。

这真的是一个问题吗?您的数据库是否有任何功能可以用来加快速度而不影响完整性?您可以通过缓存来提高性能吗?

于 2009-01-30T21:58:08.533 回答
3

规范化以对设计中的概念及其关系进行建模。想想什么样的关系可以改变,以及这样的改变对你的设计意味着什么。

在您发布的架构中,在我看来,这是一个明显的错误(如果您的组织运作方式有特殊情况,这可能不是错误)——隐含假设每个部门都在一个办公室,并且同一部门的所有员工都在该办公室工作。

如果部门占用两个办公室怎么办?

如果一名员工名义上属于一个部门,但在不同的办公室工作(假设您指的是实体办公室)怎么办?

于 2009-01-30T18:31:37.857 回答
3

不要反规范化。

根据简单而合理的设计原则设计您的表格,这将使您的系统的其余部分易于实施。易于构建、填充、使用和管理数据库。轻松快速地运行查询和更新。当情况需要时,易于修改和扩展表格设计,并且由于轻微和临时原因而无需这样做。

一组设计原则是规范化。规范化导致表易于更新(包括插入和删除)。规范化避免了更新异常,并避免了数据库自相矛盾的可能性。这通过使它们变得不可能来防止大量错误。它还通过使它们变得不必要来防止大量更新瓶颈。这很好。

还有其他一些设计原则。它们导致表格设计未完全标准化。但这不是“非规范化”。这只是一个不同的设计,与规范化有些不兼容。

导致设计与规范化完全不同的一组设计原则是星型模式设计。星型模式对于查询来说非常快。考虑到良好的 DBMS、良好的物理设计和足够的硬件来完成工作,即使是大规模的连接和聚合也可以在合理的时间内完成。如您所料,星型模式会出现更新异常。当您使数据库保持最新时,您必须围绕这些异常进行编程。您通常需要一个严格控制和精心构建的 ETL 流程,从其他(可能是规范化的)数据源更新星型模式。

使用存储在星型模式中的数据非常容易。使用某种 OLAP 和报告引擎非常简单,您无需编写任何代码即可获得所需的所有信息,并且不会过多牺牲性能。

设计一个良好的规范化模式需要良好且有些深入的数据分析。数据分析中的错误和遗漏可能会导致未发现的功能依赖关系。这些未被发现的 FD 将导致不自觉地偏离规范化。

设计和构建良好的星型模式还需要良好且有些深入的数据分析。数据分析中的错误和遗漏可能会导致维度和粒度的不幸选择。这将使 ETL 几乎不可能建立,和/或使恒星的信息承载能力不足以满足新兴需求。

好的和有些深入的数据分析不应该成为分析瘫痪的借口。分析必须在短时间内正确且合理地完成。较小的项目更短。设计和实现应该能够经受住对数据分析和需求的一些后期添加和更正,但不是稳定的需求修订洪流。

此响应扩展了您的原始问题,但我认为这与数据库设计师有关。

于 2009-01-31T14:03:53.060 回答
3

标准化是一个质量决策。

非规范化是一种性能决策。

这就是为什么 -

正常化直到它受伤; 去规范化直到它起作用。


质量决策告诉您哪种是您可以忍受的最不正常的形式:

  1. 多少非冗余对您的表很重要?
  2. 您想要多快的数据管理速度?
  3. 您希望表之间的关系有多清晰?

性能决策说明什么是可接受的最高范式:

  1. 我的数据库响应速度够快吗?
  2. 连接过多会导致速度变慢吗?

当您确定了您的情况下可接受的最低和最高范式后,请选择介于两者之间的范式。

于 2015-09-11T14:15:17.727 回答
2

如果您使用整数(或 BIGINT)作为 ID,并且它们是集群主键,那么您应该没问题。

尽管从项目中找到办公室似乎总是更快,因为您总是在查找主键,但在外键上使用索引将使差异最小化,因为索引也将覆盖主键。

如果您以后发现需要对数据进行非规范化,您可以按计划或触发器创建缓存表。

于 2009-01-30T18:12:34.120 回答
2

在示例中,在表上正确设置的给定索引应该允许连接发生得非常快,并且可以很好地扩展到 100,000 行。这通常是我解决问题的方法。

尽管有时数据只写入一次,并且在其余生中被选中,但每次执行十几个连接确实没有意义。

于 2009-01-30T18:33:28.227 回答