我应该对我的数据库进行规范化吗?

36

在设计一个数据库(例如MySQL)的模式时,是否应该完全规范化表格是一个问题。

一方面,连接操作(和外键约束等)非常缓慢;另一方面,您会得到冗余数据和潜在的不一致性。

这里的正确方法是“最后优化”吗?即按照手册规范化DB,然后查看可以去规范化以获得最佳速度增益的内容。

我对这种方法的担忧是,我将定居在可能不够快的DB设计上-但在那个阶段重构模式(同时支持现有数据)将非常痛苦。这就是为什么我想暂时忘记我学到的关于"适当的" RDBMS实践的一切,而尝试一次“扁平表”的方法的原因。

这个DB将要大量插入,这个事实会影响决策吗?


你所谈论的应用程序是什么,这很重要。 它是企业/商业逻辑、公共网站还是其他什么? - Bogdan Gusiev
@Bogdan,这是一个跟踪许多带有地理位置的对象的系统。 - Assaf Lavie
好的,你们基本上把我吓到了回到第五范式。所以谢谢。不过还是很有趣去看看这些答案。 - Assaf Lavie
BCNF应该没问题。如果您根据正确的功能依赖关系进行分解,并且您的PK-FK关系缺乏传递依赖性,那么您可能可以免费获得3NF。 - Alan
1
4NF和5NF仅对M:M关系感兴趣。 - ConcernedOfTunbridgeWells
这个回答解决了你的问题吗?如何确定数据库规范化的程度? - philipxy
9个回答

37

哲学上的答案:次优(关系)数据库充满了插入、更新和删除异常。这些都会导致不一致的数据,从而导致数据质量差。如果您不能信任数据的准确性,那么它有什么用呢?问问自己:你想要更慢但正确的答案还是更快但错误的答案?

实际问题是:在追求速度之前,先把它做对。我们人类非常不善于预测瓶颈会出现在哪里。使数据库变得很棒,经过一段合理的时间测量性能,然后再决定是否需要加速。在规范化丧失准确性之前,请尝试其他技术:您可以获得更快的服务器、连接、数据库驱动程序等吗?存储过程可能会加速吗?索引及其填充因子如何?如果这些和其他性能和调整技术无法解决问题,那么只考虑非规范化。然后测量性能,以验证您获得了所“付出”的速度增加。确保您正在执行优化而不是恶化。

[编辑]

问:那么,如果我最后进行优化,您可以推荐一种合理的方法来迁移数据吗?例如,如果我决定摆脱一个查找表-如何将现有数据库迁移到这种新设计中?

答:当然。

  1. 备份。
  2. 将备份另存到另一设备。
  3. 使用“从旧表选择插入到新表…”类型的命令创建新表。您需要进行一些联接来组合以前不同的表。
  4. 删除旧表。
  5. 重命名新表。

但是…考虑更健壮的方法:

立即在您完全规范化的表上创建一些视图。这些视图(虚拟表,数据上的“窗口”...如果您想了解更多有关此主题的信息,请问我)将具有与上面第三步相同的定义查询。编写应用程序或DB层逻辑时,请使用这些视图(至少用于读取访问;可更新的视图很有趣)。然后,如果以后需要去正则化,请按上述方法创建新表,删除视图,将新基本表重命名为视图名称。您的应用程序/DB层不会注意到区别。
实际上,这方面还有更多内容,但这应该能帮助您入门。

如果我最后进行优化,你能推荐一种合理的方法,在模式更改后迁移数据吗?例如,如果我决定摆脱一个查找表 - 我如何将现有数据库迁移到这个新设计? - Assaf Lavie
1
如果你在使用SQL Server,可以查找“Instead Of”触发器。这是我最喜欢的一种触发器。 - Raj More

16

你的数据库的使用模式(插入为主还是报告为主)一定会影响到你的规范化。此外,如果规范化表格导致显著的减速,您可能需要查看索引等方面。您正在使用哪个版本的MySQL?

一般来说,插入为主的数据库应该比报告为主的数据库更加规范化。当然,具体情况因人而异...


1
使用5.1。 您能详细说明为什么插入频繁的数据库需要更规范化吗? YMMV? - Assaf Lavie
3
由于插入操作较多,因此需要将数据库更加规范化,以便更好地捕获数据。如果是事务性操作,应该使用3NF数据库。如果是用于报告的数据库,主要关注提取信息,那么就需要使用半规范化数据库。 - Eric
1
"YMMV" = "你的结果可能会有所不同",就像汽车的燃油里程报告一样。换句话说,对于特定情况,你可能无法得到完全相同的结果。 - Turnkey
3
一般来说,规范化的数据库在获取数据时速度较慢(因为需要计算更多内容),但在存储数据时速度较快(因为需要做的工作较少)。因此,以插入为主的数据库将受益于规范化,而数据仓库数据库将受益于较少的规范化。 - David Thornley

8

一个正常的设计是开始的地方;首先要做对,因为您可能不需要使它快。

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

规范化只是以正常设计的一种方式...


5
你从哪里得到"连接(和外键约束等)非常慢"的想法?这是一个非常模糊的陈述,通常情况下我认为没有性能问题。

2
连接并非免费的。根据您的数据库规范化程度,查询速度可能会慢上许多量级。本质上,它是每个表的所有行的交叉乘积,不满足连接条件的行将被消除。这很可能已经被优化了,但仍然是一种更昂贵的操作。 - Assaf Lavie
2
@Assaf:另一方面,您可能有更少的数据,因此数据适合RAM。而您声称“本质上它是一个叉积…”就是完全错误的。它只是一个连接,没有更多,也没有更少。 - erikkallen
5
扫描良好的索引,特别是覆盖索引的连接方式非常高效。另一件需要考虑的事情是表锁定。根据您的要求,拥有多个表意味着某些插入、删除和更新可以同时安全地发生,因为它们位于不同的表中。 - Spence

5

在操作系统上很少需要使用非规范化技术。我为一个数据模型设计了近560个表(当时是澳大利亚洲最大的J2EE系统),其中只有4个部分使用了非规范化数据。两个非规范化搜索表是为了方便复杂搜索屏幕而设计的(其中一个是物化视图),另外两个则是为了满足特定性能要求而添加的。

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

最后,如果需要提高报告性能,请考虑构建数据仓库或其他单独的非规范化结构以供报告使用。实时查看大量数据计算聚合需求的报告很少出现,通常只会在少数业务线中出现。可以做到这一点的系统往往很棘手,因此成本较高。

您实际上只需要极少量真正需要最新数据的报告,它们几乎总是操作报告,例如待办事项列表或异常报告,而且涉及的数据量很小。其他所有报告都可以推送到数据仓库中,每晚刷新一次可能就足够了。


4
"优化最后"是这里的正确方法吗?即创建一个符合规范的标准化数据库,然后查看可以去规范化以实现最佳速度增益的内容。
我认为是的。我不赞成没有深思熟虑的“扁平表”数据库,因为我已经处理过太多次糟糕结构的数据库。
实际上,完全规范化的数据库通常对插入操作表现良好,因此如果它是插入密集型的,这不应该是一个因素。

4
这个问题的一般设计方法是首先将数据库完全规范化到第三范式,然后根据性能和易访问性进行必要的去规范化。这种方法往往是最安全的,因为您是通过设计做出具体决策,而不是默认情况下不规范化。
“根据需要”是需要经验的棘手部分。规范化是一种相当“按照套路”的过程,可以教授,而了解何时去规范化则不太精确,并且取决于应用程序使用和业务规则,因此会因应用程序而异。所有去规范化的决策都应该让其他专业人员支持。
例如,如果我有一个一对多的关系A到B,大多数情况下我会保持规范化,但如果我知道业务只有每个A有两个B的情况,这很可能不会改变,B记录中的数据很少,并且他们通常会将B数据与A记录一起检索,那么我最可能会在A记录中扩展两个B字段的出现次数。当然,大多数DBA会立即标记这可能是一个设计问题,因此您必须能够有说服力地证明您去规范化的理由。
从这个例子中可以看出,去规范化应该是例外。在任何生产数据库中,我预计绝大部分(95%以上)都在第三范式中,只有少数去规范化的结构。

4
在一个以插入为主的数据库中,我肯定会从规范化的表开始。如果您在查询方面遇到性能问题,我首先尝试优化查询并添加有用的索引。
只有在这样做无效时,才应该尝试非规范化的表。一定要在去规范化前后对插入和查询进行基准测试,因为很可能会降低插入速度。

3
我不知道你所说的“按照书本”的方式创建数据库是什么意思,因为我读过的大多数关于数据库的书籍都包括有关优化的主题,这与去规范化数据库设计是相同的事情。
这是一个平衡的行为,因此不要过早地进行优化。原因是去规范化的数据库设计往往变得难以处理。您需要一些指标,因此需要对数据库进行一些压力测试,以决定是否需要去规范化。
因此,规范化用于可维护性,而去规范化用于优化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接