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

时间:2009-02-02 08:10:20

标签: database database-design

我不认为我是唯一一个对此感到疑惑的人。您通常对数据库行为进行什么练习?您是否希望从数据库中删除记录?或者只是用“已删除”标志或布尔列标记记录以表示记录处于活动状态还是非活动状态更好?

9 个答案:

答案 0 :(得分:45)

这绝对取决于数据库的实际内容。如果您正在使用它来存储会话信息,那么无论如何在会话到期(或关闭)时立即擦除它,您不希望存在垃圾。因为它不能真正用于任何实际目的。

基本上,你需要问自己,我可能需要恢复这些信息吗?就像在SO上删除的问题一样,它们肯定应该被标记为“已删除”,因为我们主动允许取消删除。我们还可以选择将其显示给选择用户,而无需额外的工作。

如果您没有积极寻求完全恢复数据,但您仍然希望将其保留用于监控(或类似)目的。我建议你弄清楚(当然可能的话)聚合方案,然后把它推到另一个表。这将使您的主表清除“已删除”数据,并保持您的辅助表优化以用于监控目的(或任何您的想法)。

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

答案 1 :(得分:25)

使用删除标志的优点:

  1. 如果需要,您可以稍后获取数据,
  2. 删除操作(更新标志)可能比真正删除它更快
  3. 使用删除标志的缺点:

    1. 很容易在SQL
    2. 的某处错过AND DeletedFlag = 'N'
    3. 数据库在所有废话中找到您感兴趣的行的速度较慢
    4. 最后,你可能想要真正删除它(假设你的系统是成功的。那个记录是10岁并且在最初创建后4分钟被“删除”的情况怎么样)
    5. 无法使用自然键。您可能有一个或多个已删除的行,其中包含自然键和一个想要使用相同自然键的实际行。
    6. 为了实际删除数据,可能存在法律/合规性原因。

答案 2 :(得分:18)

作为所有帖子的补充......

但是,如果您计划对记录进行标记,则可以考虑制作视图,以获取有效记录。这样可以避免在SQL查询中写入或忘记该标志。如果您认为这也是一个目的,您可以考虑非活动记录的视图。

答案 3 :(得分:10)

我很高兴找到这个帖子。我也想知道人们对这个问题的看法。我已在许多系统上实施了“标记为已删除”约15年。每当用户打电话说出意外删除的内容时,将其标记为未删除状态要比重新创建或从备份恢复要容易得多。

我们正在使用postgresql和Ruby on rails看起来我们可以通过两种方式中的一种来修改rails或添加ondelete触发器,而是将pl / pgsql函数标记为已删除。我倾向于后者。

对于性能命中,有趣的是在大型表上查看EXPLAIN-ANALYZE的结果,以及很少的已删除项目。

在我发现的系统中,新用户倾向于做一些愚蠢的事情,例如意外删除事物。因此,当人们处于新职位时,他们拥有之前在该职位上的人的所有访问权限,除非没有经验。意外删除某些内容并能够快速恢复可以让所有人快速恢复工作。

但正如有人所说,有时你可能因某种原因需要特定的键,此时你需要真正删除它,然后重新创建记录(取消删除它并修改记录)。

答案 4 :(得分:6)

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

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

如果涉及个人信息,我会在您采用策略之前咨询您的法律部门。

答案 5 :(得分:5)

我将它们标记为已删除,并且不会删除。然而,每隔一段时间我就会扫除所有垃圾并将其存档,因此它不会扼杀性能。

答案 6 :(得分:2)

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

答案 7 :(得分:1)

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

答案 8 :(得分:0)

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

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();
}