目前正在处理项目,我们必须为大多数用户(用户角色)实施软删除.我们决定在数据库中的每个表上添加"is_deleted ='0'"字段,如果特定用户角色点击特定记录上的删除按钮,则将其设置为"1".
对于将来的维护,每个SELECT查询都需要确保它们不包含is_deleted ='1'的记录.
是否有更好的解决方案来实现软删除?
更新:我还应该注意到,我们有一个Audit数据库,用于跟踪Application数据库中所有表/字段的更改(字段,旧值,新值,时间,用户,ip).
我会倾向于使用deleted_at列的"Rails方式",该列包含删除发生的日期时间.然后,您将获得有关删除的一些免费元数据.对于SELECT,只需获取行WHERE deleted_at IS NULL
您可以对包含该WHERE IS_DELETED='0'
子句的视图执行所有查询.
使用is_deleted列是一种相当不错的方法.如果是在Oracle中,为了进一步提高性能,我建议通过在is_deleted列上创建列表分区来对表进行分区.然后删除和未删除的行将物理上位于不同的分区中,但对于您来说它将是透明的.
因此,如果您键入一个类似的查询
SELECT * FROM table_name WHERE is_deleted = 1
然后Oracle将执行"分区修剪",只查看相应的分区.在内部,分区是一个不同的表,但作为用户,它对您来说是透明的:无论是否分区,您都可以在整个表中进行选择.但Oracle将只能查询它所需的相关性.例如,假设您有1000行IS_DELETED = 0和100000行,IS_DELETED = 1,并且您在IS_DELETED上对表进行分区.现在,如果你包括条件
WHERE ... AND IS_DELETED=0
那么Oracle将只扫描1000行的分区.如果表未分区,则必须扫描101000行(两个分区).
遗憾的是,最佳响应取决于您尝试使用软删除以及您正在实现此功能的数据库.
在SQL Server中,最好的解决方案是使用类型为SMALLDATETIME或DATETIME的deleted_on/deleted_at列(取决于必要的粒度)并使该列可以为空.在SQL Server中,行标题数据包含表中每个列的NULL位掩码,因此执行IS NULL或IS NOT NULL比检查存储在列中的值要快一些.
如果您有大量数据,则需要通过数据库本身或通过两个单独的表(例如Products和ProductHistory)或通过索引视图来查看数据分区.
我通常会避免像is_deleted,is_archive等标志字段,因为它们只带有一个含义.可以为null的deleted_at,archived_at字段为您自己和继承您的应用程序的人提供了额外的意义.我避免像瘟疫这样的位掩码字段,因为它们需要了解如何构建位掩码以便掌握任何含义.
如果表很大并且性能有问题,您可以随时将"已删除"记录移动到另一个表,其中包含删除时间,删除记录等其他信息.
这样您就不必在主表中添加其他列
这取决于您需要哪些信息以及您希望支持哪些工作流程.
你想要能够:
知道那里有什么信息(在删除之前)?
知道什么时候被删除了?
知道谁删了它?
知道他们删除它时的行为能力是什么?
能够取消删除记录吗?
能够告诉它何时被删除?
等等
如果记录被删除和未删除四次,是否足以让您知道它当前处于未删除状态,或者您是否希望能够告知过渡期间发生的事情(包括连续之间的任何编辑)删除!)?
小心软删除的记录导致违反唯一性约束.如果您的数据库具有唯一约束的列,请注意先前的软删除记录不会阻止您重新创建记录.
想想周期:
创建用户(login = JOE)
soft-delete(将已删除列设置为非null.)
(重新)创建用户(login = JOE).错误.已登录LOGIN = JOE
第二次创建导致约束违规,因为login = JOE已经在软删除行中.
一些技巧:1.将删除的记录移动到新表.2.在login和deleted_at timestamp列中创建唯一性约束
我自己的意见是+1移动到新表.它需要很多纪律来维护所有查询中的*AND delete_at = NULL*(适用于所有开发人员)