启用“撤销删除”数据库实体的最佳做法是什么?

4
这是关于使用PHP/MySQL的CRM应用程序的技术内容。用户可以“删除”各种实体,如客户、联系人、备注等。我希望这些实体在应用程序中看起来被删除了,但仍然保存在数据库中,以后如果需要可以“恢复”。甚至可以在应用程序中添加一些“回收站”功能。
我想到了几种方法:
1. 将已删除的实体移动到另一个表中(例如将客户移动到customer_deleted表中)。 2. 改变实体的属性(例如将enabled改为false)。
我相信还有其他方法,每种方法都对数据库大小、性能等有自己的影响,但我想知道通常推荐的做法是什么?

customer_deleted 策略将在数据库中创建大量的结构冗余,这将是无益的。 - bzlm
2个回答

1

我会采用以下两种方式的结合:

  1. 将标志 deleted 设置为 true。
  2. 使用计划任务将条目一段时间后移动到类型为ARCHIVE 的表格中。
  3. 如果需要恢复该条目,就从档案中进行 select into ,之后再从文章表中删除它。

为什么我会选择这种方式呢?

  • 如果客户误删了某个条目,可以立即进行恢复。
  • 几周/月后,文章表可能会变得太大,因此我会将所有被删除 1 周以上的条目存档。

我不同意将“article”数据移动到另一个表中,纯粹是因为可能存在外键约束和级联操作。 - adlawson
@adlawson,我不认为需要级联操作。如果客户想要“取消删除”一篇文章,他必须查看存档。如果您有一个包含1000000个已删除文章的表格,并且在表格中的某个地方有100个活动文章,则会出现性能和存储问题。我是业务/新闻数据中心的系统管理员。这是许多CMS系统中最大的问题之一(并已被优秀的CMS公司解决)。 - Thomas Berger
点已经被接受。如果您处理的数据中,“已删除”数据远远超过“活动”数据,则将其存储在单独的表中可能会更有益。我提到的级联操作是针对文章评论或其他“子”数据类型的,其中DELETE级联很常见。连接将需要更改,并且级联操作可能需要从数据库移动到应用程序中,但这实际上取决于您的具体需求。 - adlawson
1
@adlawson 现在我明白了你的观点 =) 这就是为什么我会在一段时间后搬离,而不是立即搬离的原因。如果 CRM 系统运行了很长时间(通常它们就是为此而设计的),那么你应该关心这个问题。如果“移动间隔”是一年,在低流量系统上也应该没问题。 - Thomas Berger

0
通常的做法是设置一个 deleted_at 列,并将其设为用户删除实体的日期(默认为 null)。您还可以包括一个 deleted_by 列,用于标记谁删除了它。使用某种删除列可使 FK 关系更易于处理,因为这些关系不会断裂。通过将行移动到新表中,您将不得不更新 FK(如果您曾经取消删除,则还需再次更新)。缺点是您必须确保所有查询都排除已删除的行(如果将该行移动到新表中,则不会出现此问题)。许多 ORM 使此过滤更加容易,因此取决于您使用的内容。

好的回应。我想补充一下,Doctrine 1.2可以使用其软删除行为来实现这一点。即使您没有使用Doctrine 1.2,您也可以检查它们的实现并重现类似的模式。 - adlawson
哈!Doctrine的软删除行为是我最初学到这个的地方!它们使得在进行关联操作时轻松排除已删除的deleted_at行。Hibernate也有类似于Java的功能。 - Brad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接