就数据库而言,“正常化,正常化,性能化”是一个正确的口头禅?
规范化导致许多基本的和理想的特征,包括审美愉悦。 此外它在理论上也是“正确的”。 在这种情况下,非规范化是作为妥协来实现的,这是为了实现绩效的一种修正。 除了性能之外,还有什么原因可以使数据库非规范化?
反规范化的两个最常见的原因是:
- 性能
- 无知
前者应该通过分析进行validation,而后者应该通过卷起的报纸来纠正;-)
我想说一个更好的口头禅应该是“为了正确而规范化,为了速度而规范化 – 只有在必要的时候”
为了充分理解原始问题的导入,你必须了解系统开发中团队dynamic的一些事情,以及不同angular色/种类的人所倾向于的行为(或不当行为)。 规范化是非常重要的,因为它不仅仅是对devise模式的冷静辩论 – 它还与系统的devise和pipe理有很大关系。
数据库人员经过培训,数据完整性是一个至关重要的问题。 我们喜欢根据数据的100%正确性来考虑,所以一旦数据在数据库中,您就不必考虑或处理它在逻辑上是错误的。 这种思想学派对于规范化具有很高的价值,因为它导致(迫使)一个团队来处理数据和系统的基本逻辑。 考虑一个微不足道的例子 – 一个客户只有一个姓名和地址,或者他可以有几个? 有人需要决定,系统将会依赖于这个统一的应用规则。 这听起来像一个简单的问题,但是当你devise一个相当复杂的系统时,将这个问题乘以500倍,你会发现问题 – 规则不能只存在于纸上,必须强制执行。 一个规范化的数据库devise(具有唯一性约束,外键,检查值,逻辑执行触发器等的额外帮助)可以帮助您有一个定义良好的核心数据模型和数据正确性规则,这对于当许多人在系统的不同部分(不同的应用程序,报告等等)以及不同的人在系统上工作时,您希望系统按预期工作。 或者换一种说法 – 如果您没有办法定义和操作强制实施核心数据模型,那么您的系统就会很糟糕。
其他人(通常是经验不足的开发人员)并不这样认为。 他们认为数据库充其量只是一个被他们正在开发的应用程序所奴役的工具,或者最坏的情况下是一个可以避免的官僚作风。 (请注意,我说的是“经验不足”的开发人员,一个好的开发人员对数据库人员需要一个可靠的数据模型和数据正确性的认识是一样的,他们可能会有不同的看法,根据我的经验,只要数据库团队知道他们在做什么,并且可以对开发人员做出响应,就可以合理地在数据库层面上开展这些工作。 这些经验较less的人往往是推动非规范化的人,或多或less地成为devise和pipe理数据模型的一个快速和肮脏的工作的借口。 这就是最终如何获得与应用程序屏幕和报告1:1的数据库表,每个表反映了不同开发人员的devise假设,以及表之间的完整性缺乏一致性/一致性。 我在职业生涯中经历了几次。 开发一个系统是令人沮丧和非生产性的。
所以人们对正常化有强烈的感觉的一个原因是,这个问题是他们强烈关心的其他问题的替身。 如果你被卷入关于正常化的辩论,那就考虑各方可能为辩论带来的潜在(非技术)动机。
话虽如此,这里有一个更直接的答案,原来的问题:)
将您的数据库视为由尽可能接近逻辑devise的核心devise(高度标准化和约束)以及解决其他问题(例如稳定的应用程序接口和性能)的扩展devise组成。
您应该想限制和规范化您的核心数据模型,因为不这样做会影响数据的基本完整性以及您的系统正在构build的所有规则/假设。 如果你让这些问题离你而去,你的系统就会变得糟糕透顶。 根据需求和真实世界的数据testing核心数据模型,并像疯狂一样迭代,直到工作。 这个步骤会比build立解决scheme更像澄清要求,而且应该是这样。 使用核心数据模型作为强制function,以便为涉及的每个人获得有关这些devise问题的明确答案。
在进入扩展数据模型之前完成您的核心数据模型。 使用它,看看你能得到多远。 根据数据量,用户数量和使用模式,您可能永远不需要扩展的数据模型。 看看你能得到多less索引加上你可以在你的数据库pipe理系统中打开1,001性能相关的旋钮。
如果您真正了解了DBMS的性能pipe理function,那么您需要考虑扩展数据模型,从而增加非规范化。 请注意,这不是关于反规范化核心数据模型,而是添加处理denorm数据的新资源。 例如,如果有几个巨大的查询会影响您的性能,那么您可能需要添加一些预先计算这些查询产生的数据的表 – 实质上是预先执行查询。 保持非规范化数据与核心(标准化)数据的一致性,这样做非常重要。 例如,在支持它们的DBMS中,可以使用MATERIALIZED VIEW来自动维护denorm数据。 如果你的DBMS没有这个选项,那么也许你可以通过在底层数据存在的表上创build触发器来实现。
以一致的方式select性地去规范化数据库,以处理现实的性能挑战,而不是仅仅具有弱的数据devise,并使用性能作为理由。
当我与中低端的数据库人员和开发人员一起工作时,我坚持认为他们会产生一个绝对标准化的devise…然后可能会涉及less数更有经验的人士讨论select性非规范化问题。 在您的核心数据模型中,非规范化或多或less总是不好的。 除了核心之外,如果以一种考虑和连贯的方式来完成反规范化,则完全没有任何问题。
换句话说,从一个正常的devise去规范化到一个保留正常的同时增加一些反常规 – 处理数据的物理现实,同时保留它的基本逻辑 – 是好的。 没有正常devise核心的devise – 甚至不应该被称为非标准化,因为它们从来没有正常化过,因为它们从来没有被有意识地devise过,不过没有问题。
不要接受这样一个术语:一个软弱无力的devise是一个“非规范化”的devise。 我相信有意/非正常的非规范化数据与普通的老式数据库devise之间的混淆会导致非正规的数据,因为devise师是一个粗心大意的白痴,这是许多关于非规范化的辩论的根本原因。
非规范化通常意味着检索效率的提高(否则,为什么会这样),但是在修改(插入,更新,有时甚至是删除)操作期间,validation数据的复杂性成本很高。 大多数情况下,额外的复杂性被忽略(因为它太难以描述),导致数据库中的虚假数据,直到后来才被发现,例如当某人正试图弄清楚为什么公司破产,事实certificate,这些数据是非自相矛盾的,因为它是非规范化的。
我认为口头禅应该“正常化,正确化,只有当高层pipe理人员把工作交给其他人时才能正常化”,在这一点上,你应该接受这个机会去新的牧场,因为现在的工作可能无法生存下去我喜欢。
或者“只有当pipe理层向您发送一封电子邮件,才能免除您将要创build的混乱情况时,才能正常化”。
当然,这是假定你对公司的能力和价值有信心。
咒语几乎总是过分简化他们的题材。 这是一个例子。
规范化的优点更多的仅仅是理论或美学。 对于每个从2NF及其以后的正常forms出发,都有一个更新exception,当你不遵循正常forms时,会发生更新exception,当你按照正常forms时,exception消失。 从1NF出发是一个完全不同的蠕虫jar,我不打算在这里处理。
这些更新exception通常包括插入新数据,更新现有数据和删除行。 一般来说,您可以通过巧妙的,棘手的编程来解决这些exception问题。 接下来的问题是使用聪明的,棘手的编程的好处是值得的。 有时候成本是个错误。 有时候成本是适应性的丧失。 有时候成本其实是,不pipe信不信,performance不好。
如果你学习了各种正常的forms,你应该认为你的学习是不完整的,直到你理解了伴随的更新exception。
“非规范化”作为指导方针的问题是,它不会告诉你该怎么做。 有很多方法来使数据库非规范化。 他们大多数是不幸的,这是慈善的。 最简单的方法之一就是一次简单地去规范化一次,每次你想加快一些特定的查询。 如果不知道应用程序的历史,就会发现一个疯狂的微笑。
很多非常规化的步骤“当时似乎是一个好主意”后来变成非常糟糕的举动。
当你决定不完全正常化时,这是一个更好的select:采用一些devise规则,即使devise规范偏离完全正常化,也会产生某些好处。 作为一个例子,有星型模式devise,广泛应用于数据仓库和数据集市。 这是一种更为连贯和有纪律的方法,而不仅仅是通过奇思异想之物。 你将从星型模式devise中获得特定的好处,并且你可以将它们与你将遭受的更新exception进行对比,因为星型模式devise与规范化devise相矛盾。
通常,许多devise星型模式的人正在构build一个辅助数据库,一个不与OLTP应用程序交互的数据库。 保持数据库当前最困难的问题之一就是所谓的ETL(提取,转换和加载)处理。 好消息是,所有这些处理都可以在less量的程序中收集,处理规范化的OLTP数据库的应用程序员不必学习这些东西。 有一些工具可以帮助ETL,将数据从规范化的OLTP数据库复制到星型模式数据集市或仓库是一个很好理解的例子。
一旦你build立了一个星型模式,并且如果你select了你的维度,明智地命名你的列,特别是select了你的粒度,那么使用这个星型模式,像Cognos或Business Objects这样的OLAP工具,就像玩游戏一样简单一个电子游戏。 这允许您的数据分析师专注于分析数据,而不是学习数据的容器如何工作。
除了星图之外,还有其他一些与标准化背离的devise,但是星图更值得一提。
维度模型中的数据仓库通常以(非规范化)星型模式build模。 这些模式不是(通常)用于在线生产或交易系统。
潜在的原因是性能,但事实/维度模型还允许一些时间特征,如在传统ER风格模型中可以实现的缓慢变化的维度,但可能非常复杂和缓慢(生效date,存档表,活动logging等等)。
不要忘记,每次将数据库的一部分进行非规范化处理时,由于代码中的错误风险增加,使得整个系统的可持续性越来越差,所以进一步调整数据库的能力就会降低。
祝你好运!
数据库规范化不仅仅是为了理论上的正确性,而且可以帮助防止数据损坏。 我当然不会像@ aSkywalker所说的那样为了“简单”而去标准化。 修复和清理损坏的数据是非常简单的。
你本身没有正确的“正确性”。 这是事情:
非规范化表具有提高性能的好处,但需要冗余和更多开发人员的大脑力量。
规范化的表格有减less冗余和增加开发的便利性的好处,但需要性能。
这几乎就像一个经典的平衡方程。 因此,根据你的需要(比如有多less锤击你的数据库服务器),你应该坚持规范化的表格,除非真的需要。 然而,从标准化到非标准化的发展,反而更容易,成本也更低。
规范化与性能无关。 Erwin Smout在这个线程中所做的事情我不能说得更好: 归一化数据库对资源的影响是什么?
大多数SQL数据库pipe理系统对改变数据的物理表示的支持有限,而不会影响逻辑模型,所以不幸的是,这就是为什么你可能会发现有必要重新规范化的一个原因。 另一个原因是许多DBMS对多表完整性约束没有很好的支持,所以为了实现这些约束,你可能会被迫将一些无关的属性放到一些表中。
没门。 请记住,你应该正常化的是你的关系(逻辑层次),而不是你的表格(物理层次)。
非规格化的数据通常在没有足够标准化的地方发现。
我的咒语是“为了正确而正常化,为了performance而消除”。 RDBM是非常灵活的工具,但是针对OLTP情况进行了优化。 用更简单的方式replaceRDBMS(例如,使用事务日志的内存中的对象)可以帮助很多。
在这里,我认为人们断言标准化的数据库总是与更简单,更干净,更健壮的代码相关联。 诚然,有很多情况下,完全标准化与简单的代码相比,比部分非规范化的代码,但充其量只是一个指导,而不是一个物理定律。
有人曾经把一个词定义为一个活生生的皮肤。 在CS中,可以说一个对象或表格是根据问题的需求和现有的基础设施来定义的,而不是柏拉图式的理想对象的反映。 从理论上说,理论与实践没有区别,但在实践中,你确实find了理论上的变化。 这个说法对于CS来说特别有意思,因为这个领域的焦点之一是find这些差异,并以最好的方式来处理它们。
从事物的数据库方面来看,面向对象程序devise通过将许多密切相关的代码组合在一个对象类名称下,使我们摆脱了许多意大利面条编码的弊端它的英文含义很容易记住,并且与其相关的所有代码都适合。 如果太多的信息聚集在一起,那么在每个对象内部都会产生大量的复杂性,这让人想起意大利面代码。 如果您将群集设置得很小,那么您不能在每个对象中都没有search到大量对象信息很less的情况下遵循逻辑线程,这被称为“通心粉代码”。
如果考虑事物的编程方面的理想对象大小和规范化数据库所导致的对象大小之间的平衡,我会给予那些认为基于数据库select通常会更好的人的点头意见然后在代码中绕过这个select。 尤其是因为在某些情况下,您可以使用hibernate和类似的技术从连接创build对象。 不过,我绝不会说这是一个绝对的规则。 任何OR-Mapping层的编写都是为了使最复杂的情况变得更简单,可能会增加最简单情况下的复杂性。 请记住,复杂度不是以大小为单位来衡量的,而是以复杂度为单位的。 那里有各种不同的系统。 一些预计将增长到几千行代码,并永远停留在那里。 其他公司的目标是成为公司数据的中心门户,理论上可以在任何方向无限制地发展。 一些应用程序pipe理每次更新读取数百万次的数据。 其他人pipe理仅用于审计和临时目的的数据。 一般来说,规则是:
-
对于中型应用程序,规范化几乎总是一个好主意,当分割两边的数据都可以修改并且可能的修改彼此独立时,规范化几乎总是一个好主意。
-
更新或从单个表中select通常比使用多个表更简单,但是如果写入的OR很好,则可以将大部分数据模型空间中的差异最小化。 使用直接的SQL,这对于单个用例来说几乎是微不足道的,尽pipe它是以非面向对象的方式。
-
代码需要保持相对较小以便可pipe理,一个有效的方法是分割数据模型,并围绕各种数据模型构build一个面向服务的体系结构。 数据(de)规范化的最佳状态的目标应该被认为是在整体复杂性pipe理策略的范式之内。
在复杂的对象层次结构中,在数据库端看不到复杂性,就像级联更新一样。 如果您使用对象所有权关系对关系型外键进行build模并交叉连接,那么在更新对象时,必须决定是否级联更新。 这可能比在sql中更复杂,因为一次做某件事和正确做某件事之间的差别,就像加载数据文件和为该types的文件写入parsing器之间的差异一样。 在C ++,Java或其他任何版本中级联更新或删除的代码都需要为各种不同的场景做出正确的决定,并且这个逻辑中的错误的后果可能非常严重。 它仍然有待certificate,这是不能简化的,在SQL方面有一点灵活性,足以使任何SQL复杂性值得。
还有一个值得与正常化戒律之一划定的点。 数据库规范化的一个中心论点是数据重复总是不好的。 这是常有的事情,但不能随便地遵循,特别是当解决scheme的不同部分有不同的所有者时。 我曾经看到一种情况,一组开发人员pipe理某种types的事务,另一组开发人员支持这些事务的可审计性,所以第二组开发人员写了一个服务,每当发生事务时就创build一个非常规的表快照logging,实际上说明交易时系统的状态。 这个场景作为一个有趣的用例(至less是数据重复部分的问题),但它实际上是一大类问题的一部分。 数据一致性需求通常会对数据库中的数据结构施加一定的约束,通过使一些不正确的情况变得不可能,可以简化error handling和故障排除。 但是,这也会造成“冻结”部分数据的影响,因为更改数据子集会导致过去的事务在维度规则下失效。 很明显,某种版本控制系统需要进行sorting,所以显而易见的问题是是否使用规范化的版本控制系统(有效期和到期时间)或基于快照的方法(交易时间的价值)。 标准化版本有几个内部结构问题,您不必担心快照方法,如:
- date范围查询可以有效地完成,即使对于大型表格?
- 是否有可能保证date范围不重叠?
- 是否可以将状态事件追溯到操作员,事务或变更原因? (可能是的,但这是额外的开销)
- 通过创build更复杂的版本控制系统,您是否将正确的所有者归为正确的数据?
我认为这里的最佳目标不仅是学习理论上的正确,而且为什么它是正确的,以及违规的后果是什么,那么当你处于现实世界中时,你可以决定哪些后果是值得的哪些其他好处。 这是devise的真正挑战。
报告系统和交易系统有不同的要求。
我会build议交易系统,总是使用规范化的数据正确性。
对于报告系统,使用标准化,除非无论是什么原因需要去标准化,如特殊查询的容易性,性能等。
简单? 我不确定Steven是否会用报纸打我,但是我挂在哪里,有时非规范化的表格可以帮助报告/只读的工作人员完成他们的工作,而不会一直在窃听数据库/开发人员。