【问题标题】:How far to take normalization? [closed]标准化要走多远? [关闭]
【发布时间】:2010-10-04 12:49:59
【问题描述】:

我有这些表:

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

CreatedByIDforeign keyEmployees。我有一个几乎在每次页面加载时都会运行的查询。

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

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

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

【问题讨论】:

  • 您需要更好的 dbas,数据库中需要连接,并且它们已针对使用它们进行了优化。只有当您的 dbas 没有充分索引(FKS 需要索引)或数据量很大时,它们才会非常昂贵。即使在那儿,我也知道有些人拥有 TB 大小的数据库,但他们仍然使用联接。
  • 并且不要使用 select *。当你有一个内部连接时,你返回的列比你定义的要多(相同的数据在连接中的两列中,否则不会返回任何记录),如果你使用 select *,这可能会减慢速度,尤其是敌人每一个查询。永远不要返回超过你需要的东西。

标签: sql database-design database-normalization


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    非规范化的优点是在大型查询上快速SELECTs。

    缺点是:

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

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

    • 需要更多空间

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

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • 从 DBA 的角度来看,这是一个不敏感的答案,但其中包含智慧。
          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            我最担心的是 DBA 会警告您加入的成本,除非您处于非常病态的情况。

            【讨论】:

              【解决方案8】:

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

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

              【讨论】:

                【解决方案9】:

                标准化以对设计中的概念及其关系进行建模。想想哪些关系会发生变化,以及这样的变化对您的设计意味着什么。

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

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

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

                【讨论】:

                  【解决方案10】:

                  不要反规范化。

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

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

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

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

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

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

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

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

                  此回复扩展了您最初的问题,但我认为这与数据库设计师有关。

                  【讨论】:

                    【解决方案11】:

                    标准化是一个质量决策。

                    非规范化是一个性能决定。

                    这就是为什么-

                    正常化直到疼痛;去规范化直到它起作用。


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

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

                    绩效决定说明什么是可接受的最高范式:

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

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

                    【讨论】:

                      【解决方案12】:

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

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

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

                      【讨论】:

                      • ID 不一定需要集群以获得最佳速度。由于这些都是查找查找而不是扫描,因此在遍历 FK 时应该没有什么区别。
                      【解决方案13】:

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

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

                      【讨论】:

                      • 这应该可以很好地扩展到数百万行或更多。这是一个非常简单的查询,连接很少。但是您对索引是正确的。如果像这样的查询很慢,通常意味着他们没有索引那些没有像 PKS 那样自动索引的 FK。
                      猜你喜欢
                      • 2010-09-05
                      • 2019-09-27
                      • 2017-09-02
                      • 1970-01-01
                      • 2010-09-19
                      • 2022-01-21
                      • 2020-09-27
                      相关资源
                      最近更新 更多