实施软删除的最佳方法是什么?

目前正在进行一个项目,我们必须为大多数用户(用户angular色)实施软删除。 我们决定在数据库中的每个表上添加一个“is_deleted ='0'”字段,如果特定的用户angular色击中特定logging上的删除button,则将其设置为“1”。

为了今后的维护,每个SELECT查询将需要确保它们不包括is_deleted ='1'的logging。

有没有更好的解决scheme来实施软删除?

更新:我还应该注意到,我们有一个审计数据库,跟踪应用程序数据库中所有表/字段的变化(字段,旧值,新值,时间,用户,IP)。

您可以针对包含WHERE IS_DELETED='0'子句的视图执行所有查询。

我将倾向于使用包含删除发生的date时间的deleted_at列的“Rails方式”。 然后你会得到一些有关删除的免费元数据。 对于你的SELECT只是获取行WHERE deleted_at IS NULL

有is_deleted列是一个合理的好方法。 如果是在Oracle中,为了进一步提高性能,我build议通过在is_deleted列上创build列表分区来对表进行分区。 然后删除和未删除的行将物理上在不同的分区,但对你来说它将是透明的。

因此,如果你input一个类似的查询

 SELECT * from table_name where is_deleted = 1 

那么Oracle将执行“分区修剪”,并只查看适当的分区。 内部分区是不同的表,但对于用户来说是透明的:无论分区是否分区,您都可以在整个表中进行select。 但是Oracle只能查询所需的相关信息。 例如,假设您有1000行IS_DELETED = 0和100000行,IS_DELETED = 1,并且您将该表分区为IS_DELETED。 现在,如果你包括条件

 WHERE ... AND IS_DELETED=0 

那么Oracle将只用1000行扫描分区。 如果表未分区,则必须扫描101000行(两个分区)。

不幸的是,最好的回应取决于你要用你的软删除和你正在执行的数据库来完成什么。

在SQL Server中,最好的解决scheme是使用具有SMALLDATETIME或DATETIMEtypes(取决于所需粒度)的deleted_on / deleted_at列,并使该列可以为空。 在SQL Server中,行标题数据包含表中每个列的NULL位掩码,因此执行IS NULL或IS NOT NULL的速度比检查存储在列中的值稍快。

如果您的数据量很大,那么您需要考虑通过数据库本身或通过两个单独的表格(例如,产品和产品历史logging)或索引视图对数据进行分区。

我通常避免像is_deleted,is_archive等标志字段,因为它们只带有一个意思。 可以为空的deleted_at,archived_at字段为您自己和inheritance您的应用程序的人提供了额外的含义。 而且我避免了像鼠疫这样的掩码字段,因为它们需要理解位掩码是如何构build的以便理解任何含义。

如果表格很大,性能是一个问题,您可以随时将“已删除”的logging移动到另一个表格中,该表格具有删除时间,删除logging等附加信息

这样你就不必在主表中添加另一列

这取决于您需要的信息以及您想要支持的工作stream程。

你想能够:

  • 知道有哪些信息(删除之前)?
  • 知道它何时被删除?
  • 知道谁删除了它?
  • 当他们删除它时,知道他们的行为能力是什么?
  • 能够删除logging?
  • 能够告诉它何时被删除?
  • 等等

如果logging被删除并且未删除四次,是否足够让您知道它目前处于未删除状态,或者您是否希望能够告诉过去发生了什么(包括连续删除!)?

小心软删除logging导致唯一性约束违规。 如果您的数据库具有唯一约束的列,那么请注意先前的软删除logging不会阻止您重新创buildlogging。

想想周期:

  1. 创build用户(login = JOE)
  2. 软删除(将删除的列设置为非空)。
  3. (重新)创build用户(login= JOE)。 错误。 LOGIN = JOE已被占用

第二个创build违反约束的结果,因为login = JOE已经在软删除的行中。

一些技巧:1.将删除的logging移到新的表格中。 2.在login和deleted_at时间戳列中设置唯一性约束

我自己的意见是移动到新表+1。 它需要很多纪律来维护所有查询中的*和delete_at = NULL *(对于所有开发人员)

如果您将删除的数据移动到另一个表格(如Jim所说的),并logging删除的时间,为什么以及由谁来logging,您肯定会有更好的performance。

where deleted =0所有查询中添加where deleted =0会显着降低它们的速度,并阻碍您在表格中使用任何索引。 尽可能避免在表格中出现“旗帜”。

我在项目上使用的是statusInd tinyint not null默认情况下,使用statusInd作为位掩码的列允许我执行数据pipe理(删除,归档,复制,还原等)。 在视图中使用这个,我可以做消费应用程序的数据分配,发布等。 如果性能是关于视图的问题,那么使用小的事实表来支持这个信息,放弃这个事实,放弃关系并允许删除删除。

可以很好地进行扩展,并且以数据为中心保持数据占用空间相当小 – 对于350gb + dbs关键在于实时问题。 使用替代方法,表,触发器有一些开销,取决于需要可能或可能不适合你。

与SOX相关的审计可能需要不止一个字段来帮助您的情况,但这可能有所帮助。 请享用

你没有提到什么产品,但SQL Server 2008和Postgresql(以及其他我确定)允许你创build过滤索引,所以你可以创build一个覆盖索引,其中is_deleted = 0,减轻这种特定方法的一些负面影响。

我宁愿保留一个状态栏,所以我可以使用它的几个不同的configuration,即发布,私人,删除,needsAproval …

使用检查is_deleted = 0的视图,函数或过程,也就是说不要直接在表上select,以防由于其他原因而需要更改表

并为更大的表索引is_deleted列

由于您已经有审计跟踪,因此跟踪删除date是多余的

创build其他模式并将其全部授予您的数据模式。 在你的新模式上实现VPD,以便每个查询都有谓词,允许select未被删除的行只附加到它。 http://download.oracle.com/docs/cd/E11882_01/server.112/e16508/cmntopc.htm#CNCPT62345

@AdditionalCriteria(“this.status <>'deleted'”)

把这个放在你的@entity之上

http://wiki.eclipse.org/EclipseLink/Examples/JPA/SoftDelete