在一个全新的程序中,空间并不是什么大问题,是删除一行还是禁用一行更好,让我们说一个布尔值“禁用”并让程序忽略它?
例如,如果我想从程序中删除用户。
在一个全新的程序中,空间并不是什么大问题,是删除一行还是禁用一行更好,让我们说一个布尔值“禁用”并让程序忽略它?
例如,如果我想从程序中删除用户。
这取决于。(但你已经猜到了,我敢肯定。)
在实践中,这里对正确用法的违反几乎总是朝着删除的方向发展。
删除的主要不良后果是,当父记录消失时,其他表中的相关记录的引用完整性丢失的频率。
用于保护删除的一条红鲱鱼(您已经通过忽略存储容量问题正确处理了它)预计它将在查询效率方面产生任何明显的差异。
在很多情况下,用户或软件问题导致某人需要点击“撤消”大按钮;如果你删除了,你就不走运了(至少没有得到特别的帮助,也没有激怒你宁愿善待的人。)
我通常使用的术语是“活跃”和“不活跃”。
还有几点需要考虑(Totophil):
数据保护立法可能要求您的组织在某些情况下清除有关个人的任何可识别信息。立法因国家而异,一些指针:
另一方面,法律可能要求您保留某些信息。
不删除将为所有未来的查询创建一类新的错误。不要忘记查询编写通常由高级用户(即非 IT 专业人员)和初级开发人员完成。因此,现在每个具有仅由 BIT 活动标志标记的无效数据的表都需要在 WHERE 子句中为从现在到永远的每个查询添加一个额外的 AND。这将帮助用户陷入失败的深渊,而不是成功的深渊。但是,我强烈建议您无论如何都实施这些标志系统,因为如果没有糟糕的设计,维护开发人员就无需修复它将产生的大量错误。
表中包含历史数据的价值有多大?如果业务具有前瞻性,那么表中的旧数据可能只是一种负担——它在创建约束时会导致问题(必须修改所有约束以排除您希望不存在的数据)。由于必须不断地重新识别“我们害怕删除但再也不想使用或更新的旧垃圾”以及我们关心的新内容,数据质量保证变得复杂。
是不是因为写错了才删?如果该行对应于现实生活中的实体,那么保留并设置“已蒸发”、“死亡”、“离开建筑物”标志可能会很有趣。如果您不小心插入了与现实生活中没有实体对应的行,则 DELETE 并不是一件坏事。从未存在的假想客户对保留在客户表中很重要吗?
最后,个性起着重要作用。人们也可以成为数据的打包者。如果 DBA 保留 30 年前的所有报纸并且不喜欢删除数据,那么也许他应该确保根据优点而不是无关的个人偏好来做出数据设计决策。
在阅读了一本关于时间数据库设计的书后,我开始相信每条具有时间意义的记录都需要至少有 4 个时间戳列的理念。这四个是:创建,删除,开始,结束。创建和删除的时间戳是不言自明的。您的系统不应查看在 now() 之前已删除的记录。开始和结束列确定数据何时应用于您的系统。这是为了保留更改的历史记录。如果您需要更新记录,请将其结束时间设置为 now(),复制它,更新副本,并将副本的开始时间设置为 now()。这样,当您需要查看历史上某事的方式时,您可以让系统弄清楚。您还可以将开始设置为将来的某个时间点,以便在那时自动进行更改,或将结束设置为将来的时间以使其在那个时候自动消失。将创建/删除的时间戳设置为未来并没有什么意义......
如果您确实使用了已删除、可见、已激活等列,您可以通过使用视图来抽象出必须记住使用它的情况。
这取决于您和您的要求(当存在记录时,有些事情会变得相当困难......不要)。
不过,我会说布尔值是一个糟糕的选择。使其成为可为空的时间戳。知道何时删除某些内容非常方便,尤其是当您删除太多并想要撤消部分删除时。
这取决于。如果它被禁用,那么更容易取消删除/看到有人实际删除了记录(用于审计)。
您可能还有不删除记录的技术要求。例如,如果您想通过仅发送更改的记录来与另一个用户同步数据库,那么如果它被实际删除,您将无法做到这一点。
你需要在功能需求中有它。如果没有明确说明,您将不得不自己弄清楚。
在大多数情况下,最好将这些记录存储在单独的表中。然后,您可以避免一个表引用另一个表的各种情况,并且您需要决定是否应该将第二个表中的记录也视为已删除。
在您的表格中添加“已删除”列并标记行而不是删除它们会为您创建更多工作,而几乎没有(如果有的话)收益。现在,每次编写查询时,都必须记住包含“WHERE DELETED IS NOT NULL”(或其他)。
更好的方法是在需要删除数据时删除数据,并依靠定期备份过程来确保不会丢失任何数据。如果出于某种原因您需要将一些已删除的数据放在手边(可能是为了搜索),您最好将数据复制到为此目的创建的不同表中,然后删除原始数据。
多年来,我继承了许多数据库,不幸的是,这种标记记录而不是删除记录的策略非常普遍,并且(至少根据我的经验)总是会导致未来出现重大问题。
如果您有时需要删除的数据,但不是很频繁:您可以将记录移动到单独的数据库/表中(例如users
and users_deleted
,或者更好somedb.users
的 and somedb_deleted.users
)。
这样,仍然可以通过查询访问数据(尽管它不会像普通查询那样简单),但它不会使原始数据库混乱,您也不必围绕它编写代码。
除非您特别需要管理自己的删除,否则最好只删除行。
我想指出,(在大多数国家/地区)存在出于法律原因无法删除记录的用例。当然取决于行业和数据。
在这种情况下,我认为最佳实践指南是将“已删除”数据映射到表中,这将为您带来MatthewMartin 概述的实际删除的好处,并且通过扩展,我发现这种模式通常比创建“活动”位标志更可取我的数据表。
这应该由应用程序的需要来确定。我已经做到了两种方式。我有一些应用程序需要支持撤消,因为删除一行的成本——以及由此引起的级联删除——太昂贵了,不能拥有它。不过,通常情况下,我所做的应用程序要求用户确认删除,然后按照用户的要求进行操作。在某些情况下,出于隐私考虑,您必须删除数据。也就是说,如果用户请求删除,您需要真正删除它,而不仅仅是将其标记为非当前。在其他情况下(如与税务相关的交易),可能有理由将数据保持在非当前状态,直到法律不再要求。我有适合这两个类别的应用程序。
在您需要保留“存档”数据的情况下,可以使用各种策略。根据它是否需要立即可用,您可以将其推送到存档表,这些表要么被保留,要么被定期备份和清理。如果需要撤消,您可能希望将其保留在当前表中并通过设置标志来标记它。这实际上取决于您的架构的复杂性、应用程序的要求以及在某种程度上的个人偏好。
我正在创建一个 CRUD,我面临同样的问题。
解决方案:CRUD 的 D 应该禁用而不是删除。
问题:
大问题
我经常使用另外两种解决方案。我同意其他发布的人的观点,即这确实符合您的数据要求。
如果使用外键约束会导致引用完整性问题,您可以阻止用户删除记录(前提是您的 RDBMS 支持)。有几次我向最终用户提供了一条消息:“在解除 <parent object> 与它的关联之前,您无法删除此 <object>。” 只要您没有预料到与另一个或多个其他表存在大量关联,这就会起作用。
另一种方法是移动任何取消关联的记录以与未删除的记录相关联。例如,假设您有一门课程,其中关联了 10 个单独的上课时间。如果您删除课程,您可以允许用户决定是否删除所有 10 个课程,或者它们是否与新课程或现有课程相关联。
这是一个判断电话,但我最终在我以前认为可以删除行的表上添加了“禁用”列。我会说大多数时候添加禁用列会更安全。然而,这对于 n:n 关系可能会变得棘手,所以这是需要考虑的事情。
最好添加“已删除”列并让用户取消删除或清除已删除的项目。
正如许多人已经说过的,应用程序的需求决定了你想要做什么。但对我来说,标记一行似乎没有为正确的事情使用正确的工具。从逻辑上讲,我们将删除视为 DELETE,因此,如果出于法律原因不允许删除,则首先不要将其删除。同时,我考虑了所有内部数据结构的保存和索引。更不用说可以为检索数据进行的所有优化,但添加该检查(在视图或查询中)会随着数据库的复杂性和实体之间的关系成指数地影响性能。
简而言之,将删除逻辑放在 UI 层,以防止用户出错,并将删除权限授予应该能够删除它的用户。使用定期备份来保存档案。如果您的应用程序绝对需要严格的审计历史记录,请在触发器中实现它并将审计放在异地数据库中,以避免生产中的所有流量、检查和废话。
这取决于数据库的功能。它是所有真理的源泉吗?如果是,则禁用而不是删除,因为更容易从错误操作中恢复(即用户错误)。如果数据库来自某些上游数据源,则删除未使用的数据。上游系统可以完成任何娱乐/恢复。