【问题标题】:Is denormalization more efficient in this case?在这种情况下,非规范化是否更有效?
【发布时间】:2012-06-02 03:40:16
【问题描述】:

如需更多说明,请在此处查看我的旧帖子 Database normalization - who's right?

我很欣赏这些好的答案,但我想强调的是,我们正在制作的这个系统不仅仅是为了学习。这是我们学校真正的招生制度。我们大约四个月前开始工作,除了对非规范化的困惑之外,系统一切正常。

就像我说的,他的理由是: 1. 查询可能会被误删,造成更多问题。

  1. 他说第二范式就足够了,就像他根据过去的经验在他的所有系统中所做的那样。

  2. 与我们合作的人(没有足够的技术知识)无法从没有足够属性/行的表中进行他们想要的查询。(在我的例子中,我决定删除总单位,因为这很容易根据其他属性计算。)

  3. 计划将会计、工资、库存和采购等其他系统与注册系统集成。他说,如果是这种情况,最好将每个新系统数据库直接连接到我们的注册系统数据库,而无需访问查询。

  4. 他认为所有相关行,例如每个学生的计算平均成绩也必须包含在表中,因为他说,我们需要的是物理数据,而不是通过视图重新计算.

  5. 我猜更重要的是,他希望每笔交易都输入数据库。就像为了平衡交易而使用借记卡和贷记卡一样。

就我而言,根据我从他那里听到的消息,除了从查询中进行查询(我相信这是我们需要非规范化的主要原因)之外,他没有提到任何关于速度的内容。他只是想要数据库中记录的所有内容。

我的立场与所有这些相反。如果准确性是我们对速度的关注,那么规范化是完美的,顺便说一下我们使用的是 microsoft sql server。

最后一件事,我记得他想在 students_info 表中包含 full_name 列。他的理由?他说“从表中读取比再次查询要好。只要确保程序可以控制用户输入的全名”。

在我决定停止制作这个系统之前,请让经验丰富的人告诉我。

【问题讨论】:

  • 我的意见:如果您不是在构建一个必须快速的网站,即轻微的速度损失不是问题,那么不要反规范化。我从所描述的系统中猜测,实际记录数将相对微不足道(没有冒犯,但我将 1m 行表算作很小),无论如何您几乎不会注意到差异。我们的网络服务器可以在一分半钟内全面扫描 1700 万行表,一台体面的笔记本电脑,如果查询写得好,应该能够在一秒或更短的时间内扫描包含 50000 条记录的表。
  • 是的,现在只是很小,但我认为他想预测未来(与你的相比,这仍然相对较小!)。

标签: database system normalization denormalization


【解决方案1】:

查询可能会被意外删除,从而产生更多问题。

这就是版本控制软件的用途。此外,如果您可以“意外”删除视图,则可能会意外删除表。

他说第二范式就足够了,就像他在所有系统中所做的那样 他过去的经历。

那么他没有足够的经验。尤其是在会计方面。

我因坚持下属在 5NF 中为我提供高性能设计而闻名(或臭名昭著)。如果他们不能这样做,他们可能要么 a) 不知道 5NF 是什么,要么 b) 认为每一行都应该有一个 ID 号。 (每行都有一个 id 号会增加所需的连接数量,通常会导致性能下降,并且与规范化无关。)这两者都是很好的教育机会。

BCNF 可能足够好。 2NF 通常不是。

如果您输了这场战斗,请坚持使用 CHECK() 约束以确保总数始终正确。

与我们合作的人(没有足够的技术知识)不能 从没有足够多的表中进行他们想要的查询 属性/行。

添加一些视图将在短期内帮助您。您可能需要添加一些可更新的视图。但您有权要求那些将在生产级注册系统中处理会计数据的人员具备一定水平的技术知识。

其他系统,例如会计、工资单、库存和采购 计划与招生系统整合。如果那是 情况下,他说,最好将每个新系统数据库连接到我们的 直接注册系统数据库,无需访问查询。

视图(查询)和表共享一个命名空间。客户端代码没有说“我想连接到一个,而不是一个视图,它必须被命名为'student_payments'。”客户端代码只是说,“连接到 'student_payments'”

也就是说,有权插入付款表的任何人都更了解如何正确插入付款表。如果您最终不得不包含一个作为对其他列的计算结果的列,请坚持使用 CHECK() 约束。

系统的设计方式是所有客户端访问都通过存储过程进行,客户端代码无法直接访问表。当有效事务必须一次插入多个表时,这种方法很有意义。

他认为所有相关行,例如计算的平均成绩 每个学生也必须包含在表格中,因为我们需要什么, 他说,是物理数据,不能通过视图重新计算。

你需要的是让数据库总是给你正确的答案。

我想,更重要的是,他希望每笔交易都 输入到数据库中。就像借方和贷方的情况一样 平衡交易的目的。

最后,一些明智的事情。金融交易一般只插入。如果它们不正确,则不会更新或删除它们。相反,您插入一个补偿事务。 (而且,我希望是原因。)

实际上,我不会在第一个版本中包含计算列。只有当它们的缺席造成实际的性能问题时,我才会添加它们。

话虽如此,我在识别实际性能问题方面有一个相当高的标准。如果 Vinny 副总裁必须等待 5 秒钟才能返回查询,这并不是实际的性能问题。如果一个需要 5 秒的查询每天都在阻塞其他查询并降低整体性能,那是一个实际的性能问题。

不要根据单个 SELECT 语句的行为来确定性能问题。理想情况下,您对性能问题的确定应该基于整个系统的行为。实际上,它基于具有代表性的 SQL 语句样本的行为。 遇到性能问题之前,选择一个具有代表性的 SELECT、INSERT 和 DELETE 语句。用有代表性的样本数据测试它们,并至少存储时间。理想情况下,存储他们的执行计划和时间安排。

我不会仅仅为了在表中包含“真实”数据而包含计算列。

如果我必须通过存储计算结果来解决实际性能问题,我不会在不首先至少做这些事情的情况下发布它。

  • 如果约束要求对单行进行计算,我将包含一个 CHECK() 约束以保证计算的值始终正确。
  • 如果约束需要对多行进行计算,我会包含一个断言或触发器来实现该约束。我还会仔细查看 dbms 文档,寻找触发器可能不会触发的实例。 (在某些平台上,触发器不会在批量加载期间触发。)
  • 如果我不能使用 CHECK() 约束、断言或触发器,我会实施某种管理过程,最好在存储过程或其等效程序中进行编码,以定期搜索实际总数没有的数据' t 符合预期的总数。如果我不能在 SP 中实现它,我会在 cron 作业下运行的应用程序代码中实现它。有很多方法可以做到这一点,而不会对其他流程产生重大影响。

通常,即使我还使用声明的约束条件,我也会实施定期管理程序来检查丢失或计算错误的数据。任何拥有足够权限的人都可以出于正当理由、不正当理由或根本没有理由放弃或禁用约束。 (拥有高权限的人——包括你自己——是你最危险的用户。)

【讨论】:

  • 非常棒的回答 Catcall!但我想澄清一点。关于您对我最后一个问题的回答:“我想,更重要的是,他希望将每笔交易都输入数据库。就像借记卡和贷记卡一样,以平衡交易。”
  • 为了表中的物理数据,您是否还包括那些可以轻松计算的列(total_fee 列、forward_balance 等...)?
  • 如果只插入财务交易,不需要修改学生余额记录等其他记录。只需计算该特定学生的过去交易即可使用查询确定剩余余额,因此不需要该列。我说的对吗?
  • 谢谢。说了这么多,很多事情都清楚了。我想,我也设法赢得了我们的争论。毫无疑问,您有超过 20 年的数据库设计顾问经验!
  • 再次,我需要你的帮助。 stackoverflow.com/questions/10784757/…有什么想法吗?
【解决方案2】:

如果您要创建一个所有数据都可以更新的数据库,那么规范化是正确的方法。您希望确保当数据项发生更改时,结果会传播到各处。您可能不需要深奥的规范化范围(例如,如果您知道所有地址都在美国,则可以使用两个字符的州代码)。

为了解决“查询被删除”等问题,使用视图。这些允许您将数据的报告视图连接到基础数据结构。毕竟,最适合保持数据一致性的方法可能不适合报告。

根据我的经验,您最终将走向数据集市解决方案。您将拥有操作应用程序的标准化形式的基础数据。您将有另一组表,从这些表派生出来,用于报告目的。这些表格将是非规范化的、冗余的,并且对于不同的组看起来会有所不同——有些可以通过 Web 访问,有些可以通过 Excel 访问,有些可以提供给其他应用程序(例如预算预测)。但是,在您到达那里之前,视图应该可以很好地满足查询需求。

【讨论】:

  • 谢谢,但是当我说查询时,我的意思是查看,对不起。正如 Catcall 所说,视图和表共享同一个命名空间。
【解决方案3】:

是的,如果您正在创建数据仓库。而不是规范化并拥有数百甚至数千个表。您可以非规范化并拥有更少的表。少加入。它将更好地优化,因为查询仓库的人会更少。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 2017-03-05
    相关资源
    最近更新 更多