我参与的一个项目的首席开发人员说,依靠级联删除相关行是不好的做法。
我不明白这有多糟糕,但我想知道你对如果/为什么会这样的想法。
我参与的一个项目的首席开发人员说,依靠级联删除相关行是不好的做法。
我不明白这有多糟糕,但我想知道你对如果/为什么会这样的想法。
我会先说我很少删除行period。通常,您要保留的大多数数据。您只需将其标记为已删除,这样它就不会显示给用户(即对他们来说,它似乎已删除)。当然,这取决于数据,并且对于某些事情(例如购物车内容),当用户清空他或她的购物车时实际删除记录是可以的。
我只能假设这里的问题是您可能无意中删除了您实际上不想删除的记录。然而,参照完整性应该防止这种情况发生。因此,除了明确的情况之外,我真的看不出反对这一点的理由。
我会说你遵循最小意外的原则。
级联删除不应导致数据意外丢失。如果删除需要删除相关记录,并且用户需要知道这些记录将消失,则不应使用级联删除。相反,应要求用户明确删除相关记录,或向其提供通知。
另一方面,如果表与另一个表相关,该表本质上是临时的,或者包含一旦父实体消失就不再需要的记录,那么级联删除可能是可以的。
也就是说,我更喜欢通过删除代码中的相关记录来明确说明我的意图,而不是依赖级联删除。事实上,我从未真正使用级联删除来隐式删除相关记录。此外,正如 cletus 所述,我经常使用软删除。
我从不使用级联删除。为什么?因为太容易出错了。要求客户端应用程序显式删除(并满足删除条件,例如删除 FK 引用记录)要安全得多。
事实上,可以通过将记录标记为已删除或移动到档案/历史表中来避免删除本身。
在将记录标记为已删除的情况下,这取决于标记为已删除数据的相对比例,因为SELECT
s 必须在 ' isDeleted = false
' 上进行过滤,仅当少于 10%(大约,取决于 RDBMS)时才会使用索引记录被标记为已删除。
您更喜欢以下两种情况中的哪一种:
开发人员来找你,说“嘿,这个删除不起作用”。你们俩都调查了一下,发现他不小心试图删除整个表格内容。你们俩都笑了,然后回到你正在做的事情上。
开发人员来找你,不好意思地问“我们有备份吗?”
不使用级联 UPDATES 或 DELETES 的另一个重要原因是:它们持有一个可序列化的锁。持有可序列化的锁会降低性能。
避免级联删除的另一个重要原因是性能。在您需要从主表中删除 10,000 条记录之前,它们似乎是个好主意,而主表中又包含数百万条记录在子表中。鉴于此删除的大小,它可能会完全锁定所有表数小时甚至数天。你为什么要冒这个险?为了方便花费十分钟的时间为一条记录删除编写额外的删除语句?
此外,当您尝试删除具有子记录的记录时遇到的错误通常是一件好事。它告诉您不想删除此记录,因为您需要的数据如果这样做会丢失。级联删除将继续删除子记录,从而导致订单信息丢失,例如,如果您删除了过去有订单的客户。这种事情会彻底搞砸你的财务记录。
我同样被告知级联删除是不好的做法......因此在遇到使用它们的客户之前从未使用过它们。我真的不知道为什么我不应该使用它们,但认为它们非常方便,因为不必编写代码来删除所有 FK 记录。
因此,我决定研究为什么它们如此“糟糕”,并且从我目前发现的情况来看,它们似乎没有任何问题。事实上,到目前为止我看到的唯一好的论点是HLGLEM上面关于性能的陈述。但由于我通常不会删除这么多记录,我认为在大多数情况下使用它们应该没问题。我想听听其他人可能反对使用它们的任何其他论点,以确保我已经考虑了所有选项。
我要补充一点,ON DELETE CASCADE 使得使用二进制日志复制在数据仓库中维护数据副本变得很困难,这是大多数商业 ETL 工具的工作方式。从每个表中显式删除会维护完整的日志记录,并且对数据团队来说更容易:)
我实际上同意这里的大多数答案,但并非所有场景都是相同的,这取决于手头的情况以及该决定的熵是多少,例如:
如果您对与大量实体具有多个多/属于关系的实体有删除命令,则每次调用该删除过程时,您还需要记住从 A 的每个关系枢轴中删除所有相应的 FK与的对应关系。
而通过删除时的级联,您将其作为架构的一部分编写一次,它只会删除那些相应的 FK 并从不再需要的关系中清除枢轴,想象一个实体 + 其他实体的 24 个关系也将具有大最重要的是,关系的数量再次取决于您的设置以及您对什么感到满意。无论如何,仅供参考,在 Illuminate 迁移模式文件中,您可以这样编写:
$table->dropForeign(['permission_id']);
$table->foreign('permission_id')
->references('id')
->on('permission')
->onDelete('cascade');