目前在做一个项目,我们要对大部分用户(用户角色)实现软删除。我们决定在数据库中的每个表上添加一个“is_deleted='0'”字段,并在特定用户角色点击特定记录上的删除按钮时将其设置为“1”。

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

有没有更好的实现软删除的方案?

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

有帮助吗?

解决方案

您可以针对包含以下内容的视图执行所有查询 WHERE IS_DELETED='0' 条款。

其他提示

我会倾向于“铁路方式” deleted_at 包含的列 删除发生的日期时间. 。然后您将获得一些有关删除的免费元数据。为您 SELECT 只是获取行 WHERE deleted_at IS NULL

拥有 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 比检查列中存储的值要快一些。

如果您有大量数据,您将需要考虑通过数据库本身或通过两个单独的表(例如,产品和 ProductHistory)或通过索引视图。

我通常会避免使用 is_deleted、is_archive 等标志字段,因为它们只具有一种含义。可为空的deleted_at、archived_at字段为您自己以及继承您的应用程序的任何人提供了额外的含义。我像瘟疫一样避免位掩码字段,因为它们需要了解位掩码是如何构建的才能掌握任何含义。

这取决于您需要什么信息以及您想要支持什么工作流程。

您是否希望能够:

  • 知道那里有什么信息(在删除之前)吗?
  • 知道什么时候被删除的吗?
  • 知道是谁删的吗?
  • 知道他们删除它时以什么身份行事吗?
  • 可以取消删除记录吗?
  • 能够知道它什么时候被取消删除吗?
  • ETC。

如果该记录已被删除并未删除四次,您是否足以知道它当前处于未删除状态,或者您是否希望能够了解期间发生的情况(包括连续记录之间的任何编辑)删除!)?

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

想想循环:

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

第二次创建会导致约束冲突,因为 login=JOE 已位于软删除行中。

一些技巧:1.将删除的记录移动到新表中。2.跨登录和deleted_at时间戳列设置唯一性约束

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

如果你像 Jim 所说的那样将删除的数据移动到另一个表,并且记录删除的时间、原因和删除者,那么你肯定会有更好的性能。

添加 where deleted=0 您的所有查询都会显着减慢它们的速度,并阻碍表上可能拥有的任何索引的使用。尽可能避免在表中出现“标志”。

我在项目上使用的东西是一种状态的tinyint而不是null默认0列,使用statusind作为bitmask允许我执行数据管理(删除,存档,复制,恢复等)。在视图中使用它,我可以为消费应用程序进行数据分发、发布等。如果性能是视图的一个问题,请使用小型事实表来支持此信息,删除事实,删除关系并允许调用删除。

扩展性良好并且以数据为中心,保持数据占用量相当小 - 对于具有实时问题的 350GB 以上数据库来说是关键。使用替代方案、表、触发器会产生一些开销,根据需要,这些开销可能适合您,也可能不适合您。

SOX 相关审计可能需要多个字段来帮助您解决问题,但这可能会有所帮助。享受

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

我更喜欢保留状态列,因此我可以将它用于几种不同的配置,即已发布、私有、已删除、需要批准...

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

并对较大表的 is_deleted 列建立索引

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

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

@AdditionalCriteria("this.status <> '已删除'")

把它放在你的@entity之上

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top