我如何证明删除外键的行为不会破坏现有数据?

Agi*_*ief 5 mysql innodb foreign-key database-design referential-integrity

TL;DR:证明在实践中,alter table table_name drop foreign key constraint_name语句的执行不会破坏现有数据。重要的考虑是语句本身的执行;考虑无关紧要的事后数据更改。(打个比方:打开马厩门是有害的行为,而不是马螺栓。)

我和我的老板对于是否在 MySQL/InnoDB 数据库中使用外键有不同的看法。我赞成使用它们来强制执行 RI 并利用ON DELETE CASCADEON UPDATE RESTRICT/ SET NULL,而他反对(相信他可以在应用程序级别强制执行 RI)。

他的论点主要是:

  1. Drupal 不使用它们,没有它们也能正常工作,那我们为什么要这样做呢?
  2. 当您需要更改数据和/或结构时,它们太不灵活了。
  3. 他已将它们从现有表中删除以进行更改,这导致数据损坏仅在数周或数月后才在高流量/高活动站点上引起注意,因此他宁愿不使用它们。

我的论点主要是:

  1. 并非 Drupal 5-7(MyISAM、SQLite 3)支持的所有数据库/数据库引擎默认都强制执行FK,因此 Drupal 仅将它们保留为文档,而这在 D8 中可能有所不同。
  2. 是的,它们可能很难处理,但也许问题在于开发人员的规划/设计不当,而不是 FK。
  3. 当然,在 DBMS 级别不使用 FK 强制执行 RI 比其他方式更有可能导致数据损坏。(例如,当现有内容引用必须具有特定状态的用户时,D6 的用户引用模块不限制更改用户状态)。
  4. 让代码做/尝试 DBMS 已经做的事情是在浪费时间和资源。他如何保证他的代码与 DBMS 一样好(或比 DBMS 更好)?

从本质上讲,如果我能证明删除外键本身的行为(无论后续数据插入/更新如何)不会破坏现有数据,他就会认同我的想法。我看不出有什么方法可以证明它们的有用性/优势,因为我不确定如何令人满意地观察/记录drop foreign key执行后立即产生的效果,而不是将执行前的数据与执行后的数据进行比较。

那么,我如何通过证明以后删除/更改外键的行为不会破坏现有数据,而使用它们不会导致任何问题来说服我的老板我们应该使用外键?我如何最好地设置实际使用测试?

注意:我不太想证明我使用 FK 是正确的(从自负的角度来看),但是在 DBMS 级别使用它们比在应用程序代码中使用它们更有益于数据和应用程序代码等级。

Vér*_*ace 11

在应用程序级别实现这些东西是一场噩梦。您和您的团队将要测试,仔细检查并做复试代码EXACTLY一个已经被MySQL进行(InnoDB的),同样的事情MILLIONS过一段用户的年份

按照讨论(我已经看到了计算器的最好的一个线程)在这里我直言,您和您的团队,您的老板真的认为您可以在不到 5 年的时间内编写出具有重要功能的无错误 RI(参照完整性)代码吗?我当然不!

我无法告诉你我在其他论坛(主要是 Oracle)上读过多少次,在这些论坛上,一些可怜的混蛋正在为他继承的应用程序大哭,而 RI 是在应用程序层强制执行的。孤立的记录、无子女的父母、不一致的数据……这个名单还在继续……数据也可能是瑞士奶酪,它有很多漏洞!告诉你的老板有这样的读本书由数据库专业人员(甲骨文专家,有些是我见过的最好,最可读的技术写作)。从审查这里-什么乔纳森·刘易斯(一个人谁写了530页的大纲上只(解决)的基本原理在Oracle优化器的。

第 10 章:设计灾难,作者:Jonathan Lewis

更多战争故事,给第 8 章的粉丝!“现在准备好阅读有关‘世界上最糟糕的甲骨文项目’的所有内容。” - 乔纳森·刘易斯。

本章介绍了开发 Oracle 数据库应用程序时最常见的一些错误。您肯定会认出其中一些,因为有太多人固执地坚持某些信念。我知道,当我谈到这些常见论点时,我喜欢提出他的几点观点:
1. 我们希望我们的应用程序是“数据库独立的”。
2. 我们将在应用程序级别检查数据完整性,而不是利用 Oracle 的约束检查能力。
3. 我们想为我们的主键使用序列。

就拿小心点2的音符!如果你的老板坚持这种疯狂,那我给你的建议就是跑得快跑得远!您将在不断交火的悲惨地狱中度过每一天,永远无法发挥您作为开发人员或 DBA 的潜力,而且您将学到的很少!只是一些想法!

  • 我完全同意。即使您*可以*在*您的*应用程序中获得正确的RI,根据我的经验,任何包含有价值信息的数据库**将**被多个应用程序使用。 (2认同)

Dav*_*ett 10

直接反击积分:

Drupal 不使用它们,没有它们也能正常工作,那我们为什么要这样做呢?

Drupal 支持许多数据库层,也许其中至少有一个不支持 FK,他们选择坚持使用最低的公共功能集?很多人确实在使用它们,人们使用它们的一个数据点相对没有意义。我知道有些人在汽车上不系安全带,但我和大多数人一样...

当您需要更改数据和/或结构时,它们太不灵活了。

如果您将结构更改到需要更改 FK 关系的程度,那么您现有设计中的任何内容都可能看起来不灵活(特别是如果现有设计与您开始建模的系统不匹配,这可能就是您正在寻求改变现有结构)。

它们在更改数据时故意不灵活。它们的设计目的是不允许您以可能损害完整性的方式更改数据,即使是暂时的。询问外键约束将停止数据修改的示例,对于每个示例,我们将能够解释为什么这是一件好事以及如何使用约束来实现您的目标而不破坏它(或者相反,我们可能会而是告诉你为什么那个特定的 FK 关系是错误的——但这并不会使其他 FK 出错,它只是意味着你的模型的那部分存在问题)。

他已将它们从现有表中删除以进行更改,这导致数据损坏仅在数周或数月后才在高流量/高活动站点上引起注意,因此他宁愿不使用它们。

删除它们不会导致腐败。删除它们允许一些其他代码中的错误随着时间的推移导致损坏并且没有被注意到。如果密钥已经就位,那么该过程会引发错误,并且可能会因此注意到并修复它的问题,而不是被允许破坏更多数据直到注意到为止。删除约束所做的只是停止数据库对未来的插入/更新/删除强制执行约束——它不会影响现有数据。

我不确定您将如何向确定情况确实如此的人进行最终证明。

我能想到的唯一证据是第一原则:重申外键约束实际上做了什么,从而表明它们不允许出现不一致,如果有这个人想到的腐败的具体例子,你可以尝试创建密钥存在的问题(表明密钥会导致错误而不是允许创建不一致)。

更具体地说,关于删除约束的直接影响:表明删除它们根本不会改变现有数据。创建数据库的副本,删除副本中的键,然后对数据进行全面比较,以显示解除约束后没有任何变化。

他反对(相信他可以在应用程序级别强制执行 RI)。

最好的是不好用的开发/测试时间,在最坏的情况它会创建一个噩梦之后。您正在重新发明轮子,可能效率低下并且可能存在错误,您现在必须在每个应用程序中的代码触及该数据的任何地方实施新的轮子,并继续前进,而不是每次都简单地让数据库处理它,如果这些位中的一个代码有一个错误,数据可能会一直丢失所有应用程序的完整性。

当然,有些复杂的业务规则是 DBMS 无法为您强制执行的,因此您必须在 BL 层中实现它们,但是对于这样的基础,让 DB 处理它。

还有一个没有提到但我听过好几次:当我们对父对象进行更改时,它们效率低下

这是因为大多数 DBMS 不会自动为每个 FK 创建索引,许多人认为他们这样做了,并且对他们没有看到他们期望的性能指标感到惊讶。DB 不会这样做,因为它在不需要时可能会非常浪费(这比您预期的要频繁)。如果您需要 FK 列上的索引,以使级联更新/删除(或只是在该方向上的简单连接查询)高效,请创建一个。