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

时间:2020-03-05 18:54:53  来源:igfitidea点击:

目前正在处理一个项目,我们必须对大多数用户(用户角色)实施软删除。我们决定在数据库的每个表上添加一个" is_deleted ='0'"字段,如果特定用户角色在特定记录上单击了删除按钮,则将其设置为" 1"。

为了将来进行维护,每个SELECT查询将需要确保它们不包含is_deleted ='1'的记录。

是否有更好的解决方案来实施软删除?

更新:我还应该注意,我们有一个Audit数据库,该数据库跟踪对Application数据库中所有表/字段的更改(字段,旧值,新值,时间,用户,ip)。

解决方案

回答

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

回答

如果表很大并且性能很成问题,我们可以随时将"已删除"记录移到另一个表中,该表具有其他信息,例如删除时间,删除记录的人等

这样,我们不必在主表中添加另一列

回答

我倾向于使用" deleted_at"列向" Rails方式"倾斜,该列包含删除发生的日期时间。然后,我们会获得一些有关删除的免费元数据。对于SELECT,只需获取WHERE Deleted_at IS NULL的行

回答

这取决于我们需要哪些信息以及要支持哪些工作流程。

我们是否希望能够:

  • 知道那里有什么信息(在删除之前)?
  • 知道什么时候被删除?
  • 知道是谁删除了吗?
  • 知道他们删除时以什么身份行事吗?
  • 能够删除记录?
  • 能够知道何时将其删除?
  • 等等。

如果该记录已删除和未删除过四次,是否足以让我们知道该记录当前处于未删除状态,还是我们想知道过渡期间发生了什么(包括连续两次之间的任何编辑)删除!)?

回答

如果将已删除的数据移动到Jim所说的另一个表上,并且记录下何时删除,为什么以及由谁记录,则绝对可以提高性能。

在所有查询中添加" where 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行(两个分区)。

回答

我更喜欢保留一个状态列,因此我可以将其用于几个不同的配置,即已发布,私有,已删除,needsAproval ...

回答

使用检查is_deleted = 0的视图,函数或者过程,即不要直接在表上选择,以防表后来由于其他原因需要更改

并为更大的表索引is_deleted列

由于我们已经有了审核记录,因此跟踪删除日期是多余的

回答

我在项目上使用的是statusInd tinyint不为null的默认0列
使用statusInd作为位掩码,可以执行数据管理(删除,存档,复制,还原等)。然后,我可以在视图中使用它来为消耗性应用程序进行数据分发,发布等。如果性能是与视图有关的问题,请使用小的事实表来支持此信息,删除事实,删除关系并允许进行所谓的删除。

可以很好地扩展,并且以数据为中心,对于具有实时关注的350gb + dbs来说,保持数据占用空间非常小。使用替代项,表,触发器会产生一些开销,具体取决于需求,这可能适合我们,也可能不适合我们。

与SOX相关的审核可能需要更多的领域来解决此问题,但这可能会有所帮助。
享受

回答

遗憾的是,最佳响应取决于我们要通过软删除尝试完成的操作以及要在其中实现此操作的数据库。

在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字段为我们自己以及继承应用程序的任何人提供了更高的含义。而且,我避免使用像瘟疫这样的位掩码字段,因为它们需要了解位掩码是如何构建的,以便掌握所有含义。

回答

我们没有提到什么产品,但是SQL Server 2008和postgresql(以及其他我确定的产品)允许我们创建过滤索引,因此我们可以在is_deleted = 0处创建覆盖索引,从而减轻了此特定方法的负面影响。