我有几年在数据仓库领域使用高度非规范化数据库的经验(如果你想了解应用非规范化的场景,你应该阅读它),以及几年使用传统应用程序做OLTP。
您说公司选择切换到单个非规范化表是因为它的读写速度更快。在大多数情况下,写作绝对不更快。想象一下,如果您对区域/员工表进行非规范化。区域记录将在此表中重复数千次。如果必须更改单个区域(例如它的名称),那么您将在数千条记录中应用该更新,而规范化数据库只需要更新一条记录。这有许多严重的性能问题。第一,在任何类型的事务中,对区域的更新都会导致成千上万的员工记录以某种方式被锁定(取决于事务的类型)。快照事务将消耗大量内存。区域列上的索引将比必要的大得多。由于每个表只有一个聚集索引,您的索引优化策略会受到限制。使用规范化数据库,您可以更灵活地对单独的表进行物理排序。
要理解的最重要的一点是,您不能评估一个用例(例如选择一条记录)然后得出设计 1、2 或 3 是最好的结论。这样的测试并不代表典型的使用场景。如果您正在选择单个记录,那么您很可能正在处理一个 OLTP 场景,您选择并可能编辑单个记录。在这种情况下,如果您的测试中没有包含最常见的 CRUD 操作,那么您的测试将极其不切实际:
此外,您还必须考虑到这样一个事实,即数以千计的此类操作将同时发生,因此死锁和等待锁将导致非规范化数据库的性能非常差。当您考虑到常见的使用场景时,这将产生巨大的影响。
我所说的“单个”并不是指整个非规范化记录,我指的只是其中代表一个实体的部分。例如,更新或删除一个区域,但保留记录的员工部分,这将使您的代码更加复杂,并且性能不佳。
您可以评估的另一个场景是 OLAP,而不是 OLTP,它是数据仓库的主题领域。虽然存在使用多维数据集的 OLAP 数据库引擎,但您可以使用 OLTP 引擎实现数据仓库,但使用非规范化设计。但是,通常情况下,您不会将所有内容非规范化为单个表。通常你有一个非规范化的事实表,然后连接到它的其他表也被非规范化,以防止出现从事实表到任何其他数据的多个连接的场景。 这种类型的非规范化设计的使用场景几乎永远不会是一条记录! 通常你会聚合大量的记录(大约数百万)并且以一种方式对结构进行非规范化处理两个事情,最小化连接,并最小化记录大小(最大化每页记录)。因此,您可以从“事实”表中获得最大吞吐量。还有更多的东西。数据仓库领域非常广阔,在决定如何对数据进行非规范化时,有很多事情需要评估。好消息是它几乎被归结为一门科学。 Kimball 的“Date Warehousing Toolkit”是一本很棒的书,尽管它在概念方面有点过分,并且不会详细介绍实现细节。
重点是,您应该认识到,没有一种设计是最好的,有很多混合设计,并且每种设计都针对使用场景进行定制。
如果我是你,我会澄清我的建议,只涵盖对一种使用场景的调查,并承认在其他使用场景中其他数据库设计可能会表现更好。但在我看来,单条记录选择并不能涵盖完整的使用场景,应该包括我为 OLTP 列出的其他常见操作。
或者你可以做数据仓库的使用场景,但这里的问题是你真的需要良好的数据仓库设计技能才能进行公平的比较。很容易对数据库进行非规范化,即使在最适用的聚合报告使用场景中也会产生较差的结果。