34

在为数据库(例如 MySQL)设计模式时,会出现是否完全规范化表的问题。

一方面连接(和外键约束等)非常慢,另一方面你会得到冗余数据和不一致的可能性。

“最后优化”是正确的方法吗?即创建一个按规范规范化的数据库,然后查看可以对哪些内容进行非规范化以实现最佳速度增益。

关于这种方法,我担心的是我会选择一个可能不够快的数据库设计——但在那个阶段重构模式(同时支持现有数据)将是非常痛苦的。这就是为什么我很想暂时忘记我学到的关于“正确”RDBMS 实践的一切,并尝试一次“平面表”方法。

该数据库将插入大量的事实是否会影响该决定?

4

9 回答 9

35

一个哲学答案:次优(关系)数据库充斥着插入、更新和删除异常。这些都导致数据不一致,导致数据质量不佳。如果你不能相信你的数据的准确性,那有什么好处呢?问问自己这个问题:你想要更慢地得到正确答案还是想要更快地得到错误答案?

作为一个实际问题:在快速获得它之前先把它做好。我们人类非常不擅长预测瓶颈会发生在哪里。让数据库变得更好,在相当长的一段时间内衡量性能,然后决定是否需要让它更快。在你去规范化和牺牲准确性之前尝试其他技术:你能获得更快的服务器、连接、数据库驱动程序等吗?存储过程会加快速度吗?索引及其填充因子如何?如果这些以及其他性能和调优技术不能解决问题,那么只有考虑非规范化。然后测量性能以验证您是否获得了“付费”的速度提升。确保您正在执行优化,而不是悲观化。

[编辑]

Q:那么如果我最后优化的话,能否推荐一种合理的方式来在架构改变后迁移数据?例如,如果我决定摆脱查找表 - 我如何将现有的数据库迁移到这个新设计?

答:当然。

  1. 做好备份。
  2. 再次备份到不同的设备。
  3. 使用“从旧表中选择新表...”类型命令创建新表。您需要进行一些连接来组合以前不同的表。
  4. 删除旧表。
  5. 重命名新表。

但是......考虑一个更强大的方法:

立即在完全规范化的表上创建一些视图。这些视图(虚拟表、数据上的“窗口”......问我是否想了解更多关于该主题的信息)将具有与上述第三步相同的定义查询。当您编写应用程序或 DB 层逻辑时,请使用视图(至少用于读取访问;可更新的视图......嗯,很有趣)。然后,如果您稍后进行非规范化,则如上所述创建一个新表,删除视图,重命名新的基表,无论视图是什么。您的应用程序/数据库层不会知道其中的区别。

在实践中实际上还有更多内容,但这应该可以帮助您入门。

于 2009-06-01T12:31:43.173 回答
14

数据库的使用模式(插入重与报告重)肯定会影响您的规范化。此外,如果您发现规范化表显着放缓,您可能需要查看索引等。您使用的是哪个版本的 MySQL?

一般来说,插入繁重的数据库应该比报告繁重的数据库更加规范化。但是,YMMV 当然...

于 2009-06-01T12:18:42.230 回答
8

正常的设计是开始的地方;首先,把它做好,因为你可能不需要让它快。

对耗时连接的担忧通常是基于糟糕设计的经验。随着设计变得更加正常,设计中的表数通常会增加,而每个表中的列数和行数会减少,设计中的联合数会随着连接数的减少而增加,索引变得更有用等等。换句话说:好事发生。

规范化只是最终获得正常设计的一种方式......

于 2009-06-01T14:44:38.630 回答
5

您从哪里得到“连接(和外键约束等)非常慢”的想法?这是一个非常模糊的陈述,通常 IMO 没有性能问题。

于 2009-06-01T12:40:35.930 回答
5

在操作系统上很少需要非规范化。我为其创建数据模型的一个系统有 560 个左右的表(当时它是澳大利亚最大的 J2EE 系统),并且只有 4 条非规范化数据。其中两个项目是非规范化搜索表,旨在促进复杂的搜索屏幕(一个是物化视图),另外两个是为了响应特定的性能要求而添加的。

不要使用非规范化数据过早地优化数据库。这是持续的数据完整性问题的秘诀。此外,始终使用数据库触发器来管理非规范化数据——不要依赖应用程序来做。

最后,如果您需要提高报告性能,请考虑构建数据集市或其他单独的非规范化报告结构。结合对大量数据计算的聚合的实时视图的要求的报告很少见,而且往往只出现在少数业务线中。可以做到这一点的系统往往构建起来非常繁琐,因此价格昂贵。

您几乎可以肯定只有少量真正需要最新数据的报告,而且它们几乎总是像待办事项列表或处理少量数据的异常报告这样的操作报告。其他任何东西都可以推送到数据集市,为此每晚刷新一次可能就足够了。

于 2009-06-01T13:37:57.063 回答
4

“最后优化”是正确的方法吗?即创建一个按规范规范化的数据库,然后查看可以对哪些内容进行非规范化以实现最佳速度增益。

我会说,是的。我不得不处理结构不良的数据库太多次,以至于在没有经过深思熟虑的情况下容忍“平面表”数据库。

实际上,插入通常在完全规范化的数据库上表现良好,所以如果插入很重,这不应该是一个因素。

于 2009-06-01T12:20:01.013 回答
4

此问题的一般设计方法是首先将您的数据库完全规范化为第 3 范式,然后根据性能和易于访问进行适当的反规范化。这种方法往往是最安全的,因为您是根据设计做出具体决定,而不是默认情况下不进行规范化。

“酌情”是需要经验的棘手部分。规范化是一个可以教授的相当“死记硬背”的过程,知道在哪里进行非规范化不太精确,并且取决于应用程序的使用和业务规则,因此会因应用程序而异。您所有的非规范化决定都应该为专业人士辩护。

例如,如果我有一对多的关系,在大多数情况下,A 到 BI 会使其正常化,但如果我知道该业务只有每个 A 出现两次 B,这极不可能改变, B记录中的数据有限。他们通常会用 A 记录拉回 B 数据,我很可能会用两次出现的 B 字段来扩展 A 记录。当然,大多数合格的 DBA 会立即将其标记为可能的设计问题,因此您必须能够令人信服地证明您对非规范化的理由。

很明显,非规范化应该是个例外。在任何生产数据库中,我都希望其中的绝大多数——95% 以上——处于第三范式,只有少数非规范化结构。

于 2009-06-01T12:32:38.320 回答
4

在插入繁重的数据库上,我肯定会从规范化表开始。如果您对查询有性能问题,我会首先尝试优化查询并添加有用的索引。

只有当这没有帮助时,您才应该尝试非规范化表。请务必在非规范化之前和之后对插入和查询进行基准测试,因为您可能会减慢插入速度。

于 2009-06-01T12:35:56.097 回答
3

我不知道您对按书创建数据库是什么意思,因为我读过的大多数关于数据库的书籍都包含一个关于优化的主题,这与非规范化数据库设计相同。

这是一种平衡行为,所以不要过早优化。原因是非规范化的数据库设计往往变得难以使用。您将需要一些指标,因此对数据库进行一些压力测试,以确定您是否要进行非规范化。

因此,为了可维护性进行规范化,但为了优化而去规范化。

于 2009-06-01T14:22:07.363 回答