首页 / 知识

关于sql:实现软删除的最佳方法是什么?

2023-04-15 16:31:00

关于sql:实现软删除的最佳方法是什么?

What is the best way to implement soft deletion?

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

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

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

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


我倾向于一个deleted_at列,其中包含删除发生的日期时间。然后,您将获得一些有关删除的免费元数据。对于您的SELECT,只需获取行WHERE deleted_at IS NULL


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


具有is_deleted列是一个相当不错的方法。
如果它在Oracle中,为了进一步提高性能,我建议通过在is_deleted列上创建列表分区来对表进行分区。
然后,已删除和未删除的行实际上将位于不同的分区中,尽管对您而言它将是透明的。

结果,如果您键入类似的查询

1
SELECT * FROM TABLE_NAME WHERE is_deleted = 1

然后Oracle将执行"分区修剪",仅查看适当的分区。在内部,分区是一个不同的表,但是对用户而言它是透明的:无论是否分区,您都可以在整个表中进行选择。但是Oracle只能查询所需的分区。例如,假设您有1000个带有is_deleted = 0的行和100000个带有is_deleted = 1的行,并且在is_deleted上对表进行了分区。现在,如果您包括条件

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


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

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


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

您是否希望能够:

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

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


小心删除软记录,导致违反唯一性约束。
如果您的数据库中的列具有唯一约束,请注意,先前的软删除记录不会阻止您重新创建该记录。

考虑一下循环:

  • 创建用户(登录= JOE)
  • 软删除(将已删除的列设置为非空。)
  • (重新)创建用户(登录名= JOE)。错误。 LOGIN = JOE已被接受
  • 第二个create导致违反约束,因为在软删除的行中已经有login = JOE了。

    一些技巧:
    1.将删除的记录移到新表。
    2.在login和delete_at timestamp列中设置唯一性约束

    我个人的观点是+1以转到新表。它需要很多
    保持所有您的* AND delete_at = NULL *的纪律
    查询(适用于所有开发人员)


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

    where deleted = 0 添加到所有查询中将大大降低它们的速度,并妨碍使用表上可能具有的任何索引。尽可能避免在表中包含"标志"。


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


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

    可扩展性好,并且以数据为中心,使数据占用空间非常小-涉及实时性的350gb + dbs的关键。使用替代项,表,触发器会产生一些开销,具体取决于您的需求,这可能会也可能不会。

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


    1
    @AdditionalCriteria("this.status <> 'deleted'")

    把它放在你的@entity

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


    创建另一个架构,并将其全部授予您的数据架构。
    在新架构上放大VPD,以便每个查询都具有谓词,该谓词允许选择仅附加在其后的未删除行。
    http://download.oracle.com/docs/cd/E11882_01/server.112/e16508/cmntopc.htm#CNCPT62345


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

    并为较大的表编制is_deleted列的索引。

    由于您已经具有审核记录,因此跟踪删除日期是多余的。


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


    删除用户方法项目

    最新内容

    相关内容

    猜你喜欢