在创建数据库结构时,有哪些好的指导方针或确定数据库应该规范化到何种程度的好方法?您是否应该创建一个未规范化的数据库并随着项目的进行将其拆分?您是否应该根据性能需要创建它并完全规范化并组合表?
13 回答
您想开始设计一个规范化的数据库,直到第 3 范式。在开发业务逻辑层时,您可能会决定必须进行一些非规范化,但永远不要低于第三种形式。始终保持第一种和第二种形式的合规性。您希望为了代码的简单性而不是为了性能而进行非规范化。为此使用索引和存储过程:)
没有“随手规范化”的原因是,每次修改数据库设计时,您都必须修改已经编写得最多的代码。
有几篇不错的文章:
@GrizzlyGuru 一位智者曾经告诉我“正常化直到它受伤,非正常化直到它起作用”。
它还没有让我失望:)
我不同意以非规范化的形式开始使用它,但是,根据我的经验,它更容易调整您的应用程序以处理规范化程度较低的数据库而不是规范化程度更高的数据库。它还可能导致其工作“足够好”的情况,因此您永远无法对其进行规范化(直到为时已晚!)
规范化意味着消除冗余数据。换句话说,非规范化或非规范化数据库是一个数据库,其中相同的信息将在多个不同的地方重复。这意味着您必须编写更复杂的更新语句以确保您在各处更新相同的数据,否则您会得到不一致的数据,这反过来意味着查询的输出不可靠。
这是一个非常大的问题,所以我会说非规范化很痛苦,而不是相反。
在某些情况下,如果您认为好处大于更新数据的额外工作和数据损坏的风险,您可能会故意决定对数据库的特定部分进行非规范化。例如,对于数据仓库,出于性能原因汇总数据,并且如果在初始输入后通常不更新数据,则可以降低不一致的风险。
但总的来说,对于性能的非规范化感到厌倦。例如,非规范化连接的性能优势通常可以通过使用物化视图(也称为索引视图)来实现,这将与查询非规范化表一样快,但仍能保护数据的一致性。
Jeff 在他的博客上对他的哲学有一个很好的概述: 也许规范化是不正常的。最主要的是:不要过度标准化。但我认为更重要的一点是,它可能并不重要。除非您正在运行下一个 Google,否则在您的应用程序增长之前您可能不会注意到太大的差异。
数据库规范化我觉得是一种艺术形式。
您不希望过度规范您的数据库,因为您将拥有太多的表,这将导致您对即使是简单对象的查询也花费比应有的时间更长的时间。
我遵循的一个好的经验法则是将一遍又一遍地重复的相同信息标准化。
例如,如果您正在创建一个联系人管理应用程序,那么将 Address(Street、City、State、Zip 等)作为自己的表是有意义的。
但是,如果您只有 2 种类型的联系人,企业或个人,如果您知道您只有 2 种联系人类型表,您是否需要一个联系人类型表?对我来说没有。
我首先要弄清楚你需要的数据类型。使用建模程序来帮助像 Visio。您不想从非规范化数据库开始,因为您最终会进行规范化。首先将对象放入逻辑分组中,因为您看到重复的数据将这些数据放入新表中。我会跟上这个过程,直到你觉得你已经设计好了数据库。
让测试告诉您是否需要合并表格。编写良好的查询可以涵盖任何过度规范化。
我相信从一个未规范化的数据库开始,随着你的进步走向规范化通常是最容易开始的。对于正常化到何种程度的问题,我的理念是正常化直到开始受到伤害。这可能听起来有点轻率,但它通常是衡量走多远的好方法。
拥有规范化的数据库将为您提供最大的灵活性和最简单的维护。我总是从规范化的数据库开始,然后仅在存在需要解决的现实问题时才取消规范化。
我认为这类似于代码性能,即编写可维护、灵活的代码并在您知道存在性能问题时对性能做出妥协。
原始海报从未描述在什么情况下将使用数据库。如果它将是任何类型的数据仓库项目,在某些时候您将需要多维数据集 (OLAP) 为某些前端处理数据,那么从星型模式(事实表 + 维度)开始而不是调查会更明智正常化。在这种情况下,Kimball 书籍将有很大帮助。
我同意从规范化的数据库开始通常更好,然后进行非规范化以解决非常具体的问题,但我可能会从Boyce-Codd 范式而不是第 3 范式开始。
事实是“这取决于”。这取决于很多因素,包括:
- 代码(手动编码或工具驱动(如 ETL 包))
- 主要应用程序(事务处理、数据仓库、报告)
- 数据库类型(MySQL、DB/2、Oracle、Netezza 等)
- 数据库架构(表格、列)
- DBA 质量(主动、被动、非主动)
- 预期数据质量(您想在应用程序级别还是数据库级别强制执行数据质量?)
我同意您应该尽可能地进行规范化,并且仅在对性能绝对必要的情况下才进行非规范化。对于物化视图或缓存方案,这通常不是必需的。
要记住的是,通过规范化模型,您可以为数据库提供有关如何约束数据的更多信息,以便您可以消除不完全规范化模型中可能发生的更新异常的风险。
如果您进行非规范化,那么您要么需要忍受可能会出现更新异常的事实,要么您需要自己在应用程序代码中实现约束验证。这消除了使用 DBMS 的很多好处,它允许您以声明方式定义这些约束。
因此,假设代码质量相同,反规范化实际上可能不会给您带来更好的性能。
另一件要提的是,如今硬件很便宜,因此在问题上投入额外的处理能力通常比接受清理损坏数据的潜在成本更具成本效益。
通常,如果您在其他软件允许的范围内进行标准化,那么您就完成了。
例如,当使用对象-关系映射技术时,您将拥有一组丰富的语义,用于各种多对一和多对多关系。在引擎盖下,它将为连接表提供有效的 2 个主键。虽然相对罕见,但真正的规范化通常会为您提供与 3 个或更多主键的关系。在这种情况下,我更喜欢坚持使用 O/R 并滚动我自己的代码来避免各种数据库异常。
只是尝试使用常识。
也有人说 - 我必须同意他们 - 如果您发现自己在大多数查询中将 6 个(幻数)表连接在一起 - 不包括报告相关的 - ,那么您可能会考虑进行一些非规范化。