数据库: 删除或不删除记录

我不认为我是唯一一个对此感到疑惑的人。您通常如何练习数据库行为?您希望从数据库中物理删除记录吗?或者直接用“已删除”标志或布尔列标记记录以表示记录是活动的还是非活动的更好?

38413 次浏览

如果您担心“休眠”记录会降低数据库访问速度,那么可能需要将这些行移动到另一个充当“归档”表的表中。

我把它们标记为已删除,并没有真正删除。然而,每隔一段时间,我清除所有的垃圾和归档它,所以它不会杀死性能。

对于用户输入/管理的数据,我使用了您描述的标志方法,并给用户一个“清空垃圾”界面,以便在他们选择删除项目时实际删除它们。

这当然取决于数据库的实际内容。如果您使用它来存储会话信息,那么当会话到期(或关闭)时,一定要立即清除它,您不希望这个垃圾到处都是。因为它实际上不能再用于任何实际目的。

基本上,你需要问自己的是,我是否需要恢复这些信息?就像在 SO 上被删除的问题一样,它们肯定应该被标记为“已删除”,因为我们正在积极地允许取消删除。我们还可以选择显示它来选择用户,而不需要做太多额外的工作。

如果您没有积极地寻求完全恢复数据,但是仍然希望保留它,以便进行监视(或类似的)。我建议您找出(当然是尽可能地)一个聚合方案,然后将其推到另一个表中。这将使您的主表清除“已删除”数据,并使辅表针对监视目的(或任何您想到的目的)进行优化。

有关时态数据,请参见: http://talentedmonkeys.wordpress.com/2010/05/15/temporal-data-in-a-relational-database/

如果涉及个人资料,也会有法律问题。我认为这在很大程度上取决于您所在的位置(或者数据库所在的位置)以及使用条款是什么。

在某些情况下,人们可以要求从您的系统中删除,在这种情况下,需要进行硬删除(或者至少清除所有的个人信息)。

如果涉及到个人信息,我会在你采取策略之前和你的法律部门核实一下。

使用删除标志的优点:

  1. 如果你需要的话,可以稍后再拿回数据,
  2. 删除操作(更新标志)可能比真正删除它更快

使用 delete 标志的缺点:

  1. 在 SQL 中的某个地方很容易遗漏 AND DeletedFlag = 'N'
  2. 对于数据库来说,在所有这些垃圾中找到您感兴趣的行要慢一些
  3. 最终,您可能还是想真正删除它(假设您的系统成功的话)。如果这个记录已经存在了10年,并且在最初创建后4分钟就被“删除”了,情况又会如何呢
  4. 它可以使不可能使用一个自然的关键。您可能有一个或多个带有自然键的已删除行和一个希望使用相同自然键的真实行。
  5. 为什么要删除数据,可能有法律/合规的原因。

作为对所有职位的补充..。

但是,如果您计划标记记录,最好考虑为活动记录创建一个视图。这样可以避免在 SQL 查询中写入或忘记标志。您也可以考虑非活动记录的视图,如果您认为这也有一定的用途的话。

我很高兴找到了这条线索。我也想知道人们对这个问题的看法。我在许多系统上实现“标记为删除”已经有15年了。无论何时,当用户打电话说某些内容意外删除时,将其标记为“未删除”肯定比从备份中重新创建或恢复要容易得多。

我们正在使用 postgreql 和 Ruby on ails 看起来我们可以用两种方法中的一种来做到这一点: 修改 ails 或者添加一个 ondelete 触发器,然后使用 pl/pgsql 函数将其标记为已删除。我倾向于后者。

至于性能问题,看到 EXPLAIN-Analyze 在大型表中对少量删除项和多量删除项的结果将是非常有趣的。

我发现,在长期使用的系统中,新用户往往会做一些愚蠢的事情,比如意外地删除一些东西。因此,当人们处于一个新职位时,除了没有任何经验之外,他们拥有先前处于该职位的人的所有访问权。不小心删除了一些东西,并且能够很快恢复,这使得每个人都能很快回到工作中。

但是正如有人所说,有时候你可能因为某些原因需要那个特定的密钥,在那个时候你需要真正地删除它,然后重新创建记录(在取消删除并修改记录的时候)。

我有一个有很多依赖项的数据库。因此,我不能删除一些记录,因为其他记录仍然依赖于数据。这是我通常所做的; 我尝试删除数据,如果它工作,我知道它没有任何依赖关系,不要紧。如果没有,我会捕获错误并将其标记为非活动的:

try
{
_context.SomeTable.Remove(someEntity);
await _context.SaveChangesAsync();
}
catch (DbUpdateException ex) when (ex.InnerException is SqlException && (ex.InnerException as SqlException).Number == 547)
{
// Mark as inactive
someEntity.Active = false;
await _context.SaveChangesAsync();
}