数据库:删除或不删除记录
Posted
技术标签:
【中文标题】数据库:删除或不删除记录【英文标题】:Database: To delete or not to delete records 【发布时间】:2010-10-04 21:19:23 【问题描述】:我不认为我是唯一对此感到疑惑的人。您通常对数据库行为进行哪些练习?您更喜欢从数据库中物理删除记录吗?还是只用“已删除”标志或布尔列标记记录以表示记录是活动的还是非活动的更好?
【问题讨论】:
...无论是在数据库中承受标志的膨胀和冗余,还是将 DELETE 带到记录表中,然后通过删除,结束它们。删除,睡觉; Physical or Logical Delete of Database Record 的可能重复项 【参考方案1】:这绝对取决于您数据库的实际内容。如果您使用它来存储会话信息,那么当会话到期(或关闭)时,请务必立即擦除它,您不希望那些垃圾到处都是。因为它不能真正再次用于任何实际目的。
基本上,您需要问自己,我是否需要恢复这些信息?就像 SO 上的已删除问题一样,它们绝对应该被标记为“已删除”,因为我们正在积极允许取消删除。我们还可以选择将其显示给选择的用户,而无需做太多额外的工作。
如果您没有积极寻求完全恢复数据,但仍希望将其保留用于监控(或类似)目的。我建议您(当然在可能的范围内)找出一个聚合方案,然后将其推到另一个表中。这将使您的主表保持干净的“已删除”数据,并保持您的辅助表为监控目的(或任何您想到的)而优化。
有关时间数据,请参阅:http://talentedmonkeys.wordpress.com/2010/05/15/temporal-data-in-a-relational-database/
【讨论】:
【参考方案2】:使用删除标志的优点:
-
如果需要,您可以稍后取回数据,
删除操作(更新标志)可能比真正删除要快
使用删除标志的缺点:
-
很容易在 SQL 中的某处遗漏
AND DeletedFlag = 'N'
数据库在所有垃圾中查找您感兴趣的行会变慢
最终,您可能还是想真正删除它(假设您的系统是成功的。如果该记录已有 10 年历史,并且在最初创建 4 分钟后被“删除”)
它可能会导致无法使用自然键。您可能有一个或多个已删除的行使用自然键,而真实行想要使用相同的自然键。
您可能出于法律/合规原因实际删除数据。
【讨论】:
【参考方案3】:作为对所有帖子的补充...
但是,如果您打算标记记录,最好考虑为活动记录创建视图。这将使您免于编写或忘记 SQL 查询中的标志。如果您认为这也有目的,您也可以考虑查看非活动记录。
【讨论】:
【参考方案4】:我很高兴找到这个帖子。我也想知道人们对这个问题的看法。我已经在许多系统上实施了大约 15 年的“标记为已删除”。每当用户打电话说某些内容被意外删除时,将其标记为未删除肯定比重新创建它或从备份中恢复要容易得多。
我们在 Rails 上使用 postgresql 和 Ruby,看起来我们可以通过以下两种方式之一来做到这一点,修改 rails 或添加 ondelete 触发器,然后使用 pl/pgsql 函数将其标记为已删除。我倾向于后者。
至于性能命中,看看 EXPLAIN-ANALYZE 在大表上对少数已删除项目和许多已删除项目的结果会很有趣。
我发现在长期使用的系统中,新用户往往会做一些愚蠢的事情,比如意外删除内容。因此,当人们是新职位时,除了零经验外,他们拥有之前担任该职位的人的所有访问权限。意外删除某些内容并能够快速恢复让每个人都能快速恢复工作。
但正如有人所说,有时您可能出于某种原因需要恢复该特定密钥,此时您需要真正删除它,然后重新创建记录(取消删除并修改记录)。
【讨论】:
【参考方案5】:我将它们标记为已删除,并没有真正删除。但是,我每隔一段时间就会清除所有垃圾并将其存档,因此不会影响性能。
【讨论】:
【参考方案6】:如果涉及个人数据,无论哪种方式都存在法律问题。我认为这很大程度上取决于您在哪里(或数据库在哪里),以及使用条款是什么。
在某些情况下,人们可能会要求从您的系统中删除,在这种情况下需要硬删除(或至少清除所有个人信息)。
如果涉及个人信息,我会在您采取任何一种策略之前咨询您的法律部门。
【讨论】:
【参考方案7】:如果您担心“休眠”记录会减慢您的数据库访问速度,您可能希望将这些行移动到另一个充当“归档”表的表中。
【讨论】:
【参考方案8】:对于用户输入/管理的数据,我使用了您描述的标志方法,并为用户提供了一个“清空垃圾箱”界面,以便在他们选择时实际删除项目。
【讨论】:
【参考方案9】:我有一个包含很多依赖项的数据库。因此,我无法删除一些记录,因为其他记录仍然依赖于数据。这是我通常做的;我尝试删除数据,如果它有效,我知道它没有任何依赖关系并且没关系。如果没有,我会捕获错误并将其标记为不活动:
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();
【讨论】:
以上是关于数据库:删除或不删除记录的主要内容,如果未能解决你的问题,请参考以下文章