物理与逻辑/软删除数据库记录?

时间:2008-12-18 16:09:33

标签: sql database soft-delete

对记录进行逻辑/软删除(即设置一条表明记录已被删除的标志)与实际或物理删除记录相比有什么好处?

这是常见做法吗?

这安全吗?

26 个答案:

答案 0 :(得分:63)

优点是您保留历史记录(适用于审计),并且您不必担心通过引用要删除的行的数据库中的各种其他表级联删除。缺点是您必须编写任何报告/显示方法以将标记考虑在内。

如果这是一种常见的做法 - 我会说是的,但与使用它的任何事情一样,取决于您的业务需求。

编辑:想到另一个不利因素 - 如果表上有唯一索引,删除的记录仍将占用“一”记录,因此您必须围绕这种可能性进行编码(例如,具有用户名上的唯一索引;删除的记录仍然会阻止已删除的用户新用户记录的用户名。解决这个问题你可以使用已删除的用户名列的GUID,但这是一个非常hacky的解决方法我不建议。可能在那里情况,最好只有一个规则,一旦使用用户名,它永远不会被替换。)

答案 1 :(得分:24)

逻辑删除是否常见?是的,我在很多地方都见过这个。他们安全吗?这真的取决于它们在您删除数据之前的数据是否安全性较低?

当我担任技术主管时,我要求我们的团队保留每一段数据,当时我知道我们将使用所有数据来构建各种BI应用程序,尽管当时我们不知道什么要求是。虽然从审计,故障排除和报告的角度来看这很好(这是B2B交易的电子商务/工具网站,如果有人使用工具,我们想要记录它,即使他们的帐户后来被关闭),它确实有几个缺点。

缺点包括(不包括已经提及的其他人):

  1. 保持所有数据的性能影响,我们制定各种归档策略。例如,应用程序的一个区域接近每周生成大约1Gb的数据。
  2. 保持数据的成本确实随着时间的推移而增长,而磁盘空间便宜,在线和离线保存和管理数据量的基础设施数量很多。冗余需要大量磁盘,人们有时间确保备份快速移动等。
  3. 在决定使用逻辑,物理删除或存档时,我会问自己这些问题:

    1. 是否需要将此数据重新插入表中。例如,用户帐户适合此类别,因为您可能激活或停用用户帐户。如果是这种情况,逻辑删除最有意义。
    2. 存储数据有什么内在价值吗?如果是这样,将生成多少数据。根据这一点,我要么采用逻辑删除,要么实施归档策略。请记住,您始终可以归档逻辑删除的记录。

答案 2 :(得分:15)

可能有点晚了,但我建议大家查看关于逻辑/软删除的Pinal Dave's blog post

  

我根本不喜欢这种设计[软删除]。我坚信只有必要数据应该在单个表中并且无用数据应该移动到存档表的体系结构。我没有关注isDeleted列,而是建议使用两个不同的表:一个包含订单,另一个包含已删除的订单。在这种情况下,您将不得不维护两个表,但实际上,它很容易维护。将UPDATE语句写入isDeleted列时,将INSERT INTO写入另一个表并从原始表中删除它。如果情况是回滚,则以相反的顺序写入另一个INSERT INTO和DELETE。如果您担心事务失败,请将此代码包装在TRANSACTION中。

     

在上述情况下,较小的表与较大的表有什么优点?

     
      
  • 较小的表格易于维护
  •   
  • 索引重建操作要快得多
  •   
  • 将存档数据移动到另一个文件组将减少主文件组的负载(考虑到所有文件组都在不同的系统上) - 这也将加快备份速度。
  •   
  • 由于规模较小,统计数据会频繁更新,这将减少资源消耗。
  •   
  • 索引的大小会更小
  •   
  • 桌子的性能会随着桌子尺寸的缩小而提高。
  •   

答案 3 :(得分:12)

我是一名NoSQL开发人员,在我上一份工作中,我使用的数据对某人来说一直很重要,如果在创建的同一天意外删除了数据,我就无法找到它。昨天的最后一次备份!在那种情况下,软删除总能节省一天。

我使用时间戳进行软删除,注册文档被删除的日期:

IsDeleted = 20150310  //yyyyMMdd

每个星期天,一个进程走在数据库上并检查IsDeleted字段。如果当前日期和时间戳之间的差异大于N天,则文档被硬删除。考虑到文档仍然可以在某些备份中使用,这样做是安全的。

编辑:这个NoSQL用例是关于在数据库中创建的大文档,每天数十或数百个,但不是数千或数百万。通常,它们是具有工作流程的状态,数据和附件的文档。这就是为什么用户可能删除重要文件的原因。该用户可以是具有管理员权限的人,也可以是文档的所有者,仅举几例。

TL; DR我的用例不是大数据。在这种情况下,您将需要一种不同的方法。

答案 4 :(得分:8)

我使用的一种模式是创建镜像表并在主表上附加触发器,因此所有删除(如果需要,还会更新)都会记录在镜像表中。

这允许你重建"删除/更改记录,您仍然可以在主表中进行硬删除并保持"清理" - 它还允许创建"撤消"功能,您还可以记录在镜像表中执行操作的日期,时间和用户(在搜寻情况下非常有用)。

另一个优点是,在查询主要文件时不会意外包含已删除的记录,除非您故意在镜像表中包含记录(您可能希望显示实时和已删除的记录)。

另一个优点是镜像表可以独立清除,因为它不应该有任何实际的外键引用,与从使用软删除但仍具有引用连接的主表清除相比,这是一个相对简单的操作。其他表格。

还有什么其他优势? - 如果您有一群编程人员在项目上工作,使用混合技能读取数据库并注意细节级别,那就太棒了,你不必熬夜希望他们中的一个不忘记不包括已删除的记录(lol,Not Include Deleted Records = True),这导致夸大其词之类的话说客户可用的现金头寸然后他们去购买一些股票(即,就像在交易系统中一样),当你使用交易系统时,你会很快发现稳健解决方案的价值,即使它们可能有更多的初始"开销"。

<强>例外:
- 作为指南,使用软删除&#34;参考&#34;用户,类别等数据,以及对镜像表的硬删除事实&#34;事实&#34;类型数据,即交易历史。

答案 5 :(得分:4)

我几乎总是软删除,这就是原因:

  • 如果客户要求您执行此操作,则可以恢复已删除的数据。软删除更快乐的客户。从备份中恢复特定数据非常复杂
  • 检查isdeleted到处都不是问题,你必须检查userid(如果数据库包含来自多个用户的数据)。您可以通过将这两个检查放在单独的函数(或使用视图)上来执行代码检查
  • 优雅删除。处理已删除内容的用户或进程将继续“查看”它,直到它们进入下一次刷新。如果进程正在处理突然删除的某些数据,这是一个非常理想的功能
  • 同步:如果您需要在数据库和移动应用之间设计同步机制,您会发现软删除更容易实现

答案 6 :(得分:3)

回复:“这安全吗?” - 这取决于你的意思。

如果您的意思是通过执行物理删除,您将阻止任何人找到已删除的数据,然后是,这或多或少是真的;你在物理上删除需要删除的敏感数据更安全,因为这意味着它永久地从数据库中消失了。 (但是,要意识到可能存在相关数据的其他副本,例如备份,或事务日志,或传输中的记录版本,例如数据包嗅探器 - 只是因为您从数据库中删除不保证它没有保存在其他地方。)

如果您的意思是通过逻辑删除,您的数据更安全,因为您永远不会丢失任何数据,这也是正确的。这对审计方案很有用;我倾向于采用这种方式设计,因为它承认了这样一个基本事实:一旦生成了数据,它就永远不会真正消失(特别是如果它曾经具有被互联网搜索缓存的能力)发动机)。当然,真正的审计场景要求不仅要删除逻辑,还要记录更新,以及更改时间和进行更改的角色。

如果您的意思是数据不会落入任何不应该看到它的人手中,那么这完全取决于您的应用程序及其安全结构。在这方面,逻辑删除不会比数据库中的任何其他内容更安全或更不安全。

答案 7 :(得分:3)

我非常喜欢逻辑删除,特别是对于业务线应用程序,或者在用户帐户的上下文中。我的理由很简单:通常我不希望用户再次使用系统(因此帐户被标记为已删除),但如果我们删除了用户,我们将失去他们所有的工作等等。

另一种常见情况是用户可能会在删除后重新创建一段时间。对于用户而言,将所有数据存储为删除之前的状态是一种更好的体验,而不是必须重新创建它。

我通常认为删除用户更多是无限期地“暂停”它们。你永远不知道什么时候他们合法地需要回来。

答案 8 :(得分:3)

我通常使用逻辑删除 - 我发现当你还间歇性地将'已删除'数据存档到存档表(如果需要可以搜索)时它们运行良好,因此不会影响应用程序的性能。< / p>

它运作良好,因为如果您经过审核,您仍然拥有数据。如果你在物理上删除它,它就消失了

答案 9 :(得分:2)

如果您想保留某些内容的历史记录(例如@Jon Dewees提到的用户帐户),这是相当标准的。如果用户有很大的机会要求取消删除,那肯定是一个好主意。

如果您担心从查询中过滤掉已删除的记录的逻辑变得混乱并且只是使查询复杂化,那么您可以构建为您进行过滤的视图并对其使用查询。它可以防止这些记录在报告解决方案等中泄漏。

答案 10 :(得分:2)

如果参照完整性很难,则进行逻辑删除。

当表数据存在时间方面(有效期为FROM_DATE - TO_DATE)时,这是正确的想法。

否则将数据移至审核表并删除记录。

好的一面:

这是更简单的回滚方式(如果可能的话)。

很容易看出特定时间点的状态是什么。

答案 11 :(得分:2)

我强烈不同意进行逻辑删除,因为您遇到了很多错误。

首先,每个查询都必须注意IsDeleted字段,并且在复杂查询时错误的可能性会更高。

第二个性能:想象一个包含100000个recs的表,只有3个活动,现在将这个数字乘以数据库的表;另一个性能问题是可能与旧记录(已删除记录)的新记录发生冲突。

我看到的唯一优势是记录的历史记录,但还有其他方法可以实现此结果,例如,您可以创建一个记录表,您可以在其中保存信息: TableName,OldValues,NewValues,Date,User,[..] 其中*Values可以是varchar,并以此格式fieldname : value写下详细信息; [..]或将信息存储为xml

所有这些都可以通过代码或触发器来实现,但您只有 ONE 表,其中包含您的所有历史记录。 另一个选项是查看指定的数据库引擎是否是对跟踪更改的本机支持,例如在SQL Server数据库上有SQL Track Data Change。

答案 12 :(得分:2)

需要回答系统设计之外的要求。记录保留的法律或法定要求是什么?根据与行相关的内容,可能存在法律要求,即数据在被暂停后会保留一段时间。

另一方面,要求可能是一旦记录被删除,就会真正且不可撤销地删除。在做出决定之前,请与利益相关者讨论。

答案 13 :(得分:2)

依赖于同步的移动应用程序可能会强制使用逻辑而不是物理删除:服务器必须能够向客户端指示记录已被(标记为)已删除,如果记录是物理删除。

答案 14 :(得分:2)

我曾经做过软删除,只是为了保留旧记录。我意识到用户并不像我想的那样经常查看旧记录。如果用户想要查看旧记录,他们只能从归档或审计表中查看,对吧?那么,软删除的优势是什么?它只会导致更复杂的查询语句等。

在我决定不再进行软删除之前,我已经实现了以下内容:

  1. 实施审核,记录所有活动(添加,编辑,删除)。确保没有链接到审计的外键,并确保此表是安全的,除管理员外没有人可以删除。

  2. 确定哪些表被视为“事务表”,很可能会将其保留很长时间,并且用户可能希望查看过去的记录或报告。例如;购买交易。此表不仅应保留主表的id(例如dept-id),还应保留其他信息(如名称作为引用(例如dept-name))或任何其他必要的报告字段。

  3. 实现主表的“活动/非活动”或“启用/禁用”或“隐藏/显示”记录。因此,用户可以禁用/禁用主记录,而不是删除记录。这样更安全。

  4. 只是我的两分钱意见。

答案 15 :(得分:1)

要回复Tohid的评论,我们遇到了同样的问题,我们希望保留记录的历史记录,而且我们也不确定是否需要is_deleted列。

我说的是我们的python实现和我们遇到的类似用例。

我们遇到https://github.com/kvesteri/sqlalchemy-continuum,这是获取相应表的版本控制表的简便方法。最小代码行并捕获添加,删除和更新的历史记录。

这不仅仅是is_deleted列。您可以随时反映版本表以检查此条目发生了什么。是否删除,更新或添加了条目。

这样我们根本不需要is_deleted列,我们的删除功能非常简单。这样我们也不需要记住在任何api中标记is_deleted=False

答案 16 :(得分:1)

我只是想扩展提到的唯一约束问题。

假设我有一个包含两列的表:idmy_column.为了支持软删除,我需要将表定义更新为:

create table mytable (
  id serial primary key,
  my_column varchar unique not null,
  deleted_at datetime
)

但是,如果对行进行软删除,则我希望忽略my_column约束,因为删除的数据不应干扰未删除的数据。我原来的模型不起作用。

我需要将数据定义更新为此:

create table mytable (
  id serial primary key,
  my_column varchar not null,
  my_column_repetitions integer not null default 0,
  deleted_at datetime,
  unique (my_column, my_column_repetitions),
  check (deleted_at is not null and my_column_repetitions > 0 or deleted_at is null and my_column_repetitions = 0)
)

并应用此逻辑:当当前行(即未删除)时,my_column_repetitions应保留默认值0,而当该行被软删除时,其my_column_repetitions必须为默认值。更新为(max. number of repetitions on soft-deleted rows) + 1.

后一种逻辑必须通过触发器以编程方式实现,或者在我的应用程序代码中进行处理,并且没有检查是否可以设置。

针对每个唯一列重复此操作!

我认为该解决方案确实很不可靠,因此希望使用单独的 archive 表来存储已删除的行。

答案 17 :(得分:1)

他们不会让数据库执行,因为它应该渲染级联功能无用。

对于简单的事情,例如插入,在重新插入的情况下,它背后的代码加倍。

您不能简单地插入,而是必须检查存在并插入(如果它之前不存在)或更新删除标记(如果存在)同时还将所有其他列更新为新值。这被视为数据库事务日志的更新,而不是新的插入导致不准确的审计日志。

它们会导致性能问题,因为表格会被冗余数据打包。它通过索引特别是具有唯一性来发挥作用。

我不是逻辑删除的忠实粉丝。

答案 18 :(得分:0)

嘛!正如大家所说,这取决于具体情况。

如果您有像UserName或EmailID这样的列的索引,并且您再也不希望使用相同的UserName或EmailID;你可以使用软删除。

也就是说,总是检查SELECT操作是否使用主键。如果SELECT语句使用主键,则添加带WHERE子句的标志不会有太大区别。我们举个例子(Pseudo):

表用户(UserID [主键],EmailID,IsDeleted)

SELECT * FROM Users where UserID = 123456 and IsDeleted = 0

由于UserID列具有主键,因此该查询在性能方面不会有任何差异。最初,它将根据PK扫描表格,然后执行下一个条件。

软删除无法完成的情况:

在主要所有网站上注册都会将EmailID作为您的唯一标识。我们非常清楚,一旦在Facebook,G +这样的网站上使用EmailID,它就不能被其他人使用。

有一天,用户想要从网站上删除他/她的个人资料。现在,如果您进行逻辑删除,该用户将无法再次注册。此外,使用相同的EmailID再次注册并不意味着恢复整个历史记录。大家都知道,删除意味着删除。在这种情况下,我们必须进行物理删除。但是为了维护帐户的整个历史记录,我们应该始终将这些记录存档在存档表或已删除的表中。

是的,在我们有很多外国牌桌的情况下,处理非常麻烦。

还要记住,软/逻辑删除会增加表的大小,因此索引大小会增加。

答案 19 :(得分:0)

大多数情况下使用softdeleting是因为你不想公开某些数据,但是你必须保留它,因为历史原因(产品可能会停产,所以你不需要任何新的交易,但你仍然需要与销售交易历史一起工作)。顺便说一下,有些人正在复制销售交易数据中的产品信息值,而不是引用产品来处理这个问题。

实际上,它看起来更像是可见/隐藏或活动/非活动功能的重写。因为这就是商业世界中“删除”的含义。我想说终结者可能会删除人,但老板只会解雇他们。

这种做法是非常常见的模式,并且由于很多原因而被许多应用程序使用。因为这不是实现这一目标的唯一方法,所以你会有成千上万的人说这是好的或废话,而且都有很好的论据。

从安全性的角度来看,SoftDelete不会取代审计工作,也不会取代备份工作。如果您害怕“在两个备份案例之间插入/删除”,您应该阅读有关完整或批量恢复模型的信息。我承认SoftDelete可以使恢复过程更加微不足道。

由您了解您的要求。

答案 20 :(得分:0)

为了提供替代方案,我们让用户使用通过MobiLink进行远程设备更新。如果我们删除服务器数据库中的记录,那些记录永远不会在客户端数据库中被标记为已删除

所以我们两个都做。我们与客户合作确定他们希望能够恢复数据的时间。例如,通常客户和产品处于活动状态,直到我们的客户说他们应该被删除,但销售历史仅保留13个月,然后自动删除。客户可能希望将已删除的客户和产品保留两个月,但保留历史记录六个月。

因此我们在一夜之间运行一个脚本,根据这些参数标记逻辑删除的内容,然后两六个月后,今天标记为逻辑删除的任何内容都将被删除。

我们对数据安全性的关注要少于在内存有限的客户端设备上拥有大量数据库,例如智能手机。一个客户每周两次订购200件产品,为期四年,将有超过81,000行的历史,其中75%的客户如果看到他们就不在乎。

答案 21 :(得分:0)

这一切都取决于系统的用例及其数据。

例如,如果您正在谈论政府监管系统(例如,制药公司的系统被认为是质量体系的一部分,并且必须遵循FDA的电子记录指南),那么您最好不要努力删除!来自FDA的审核员可以进入并询问系统中与产品编号ABC-123相关的所有记录,并且可以更好地获得所有数据。如果您的业务流程所有者表示系统不允许任何人在未来的新记录中使用产品编号ABC-123,请使用软删除方法使其成为&#34;非活动&#34;在系统内,仍然保留历史数据。

但是,也许您的系统及其数据有一个用例,例如&#34;跟踪北极的天气&#34;。也许你每小时都要读一次温度读数,并在一天结束时累计每日平均值。也许在聚合后不再使用每小时数据,并且您在创建聚合后硬删除每小时读数。 (这是一个简单的,简单的例子。)

关键是,这一切都取决于系统的使用情况及其数据,而不是纯粹从技术角度做出决定。

答案 22 :(得分:0)

软删除是一种编程习惯,当数据更相关时,大多数应用程序都会遵循这种做法。考虑一个金融应用案例,其中最终用户的错误删除可能是致命的。 软删除变得相关时就是这种情况。在软删除中,用户实际上并没有从记录中删除数据,而是将其标记为IsDeleted为true(按照常规约定)。

在EF 6.x或EF 7中,软件删除作为属性添加,但我们现在必须创建一个自定义属性。

我强烈推荐SoftDelete在数据库设计中,它是编程实践的一个很好的惯例。

答案 23 :(得分:0)

我已经回答了in another post。 但是,我认为我的答案更适合这里的问题。

  

我对软删除的实用解决方案是通过创建一个新文件来进行归档   表格,其中包含以下列:original_idtable_namepayload,   (和可选的主键`id)。

     

original_id是已删除记录的原始ID,table_name   是已删除记录的表名(在您的情况下为"user"),   payload是已删除的所有列中的JSON字符串化字符串   记录。

     

我还建议在original_id列上为其建立索引   数据检索。

     

通过这种方式存档数据。您将拥有这些优势

     
      
  • 跟踪历史记录中的所有数据
  •   
  • 无论删除的记录的表结构如何,只有一个地方可以存储任何表中的记录
  •   
  • 不用担心原始表中的唯一索引
  •   
  • 不用担心在原始表中检查外来索引
  •   
  • 每个查询中没有更多WHERE子句可以检查是否删除
  •   
     

已经是讨论   here解释原因   在实践中,软删除不是一个好主意。软删除介绍   将来可能会遇到一些麻烦,例如记录记录,...

答案 24 :(得分:0)

优点是数据保存/持久化。当从具有大量软删除的表中查询或检索数据时,性能下降将是浪费。在我们的情况下,我们将两者结合使用:就像其他人在先前的答案中提到的那样,例如,我们soft-delete users/clients/customershard-deleteitems/products/merchandise表中有重复记录的表上不需要养蜂。

答案 25 :(得分:0)

要视情况而定,请考虑以下因素:

通常,您不需要“软删除”记录。 保持简单和快速。 例如删除不再可用的产品,因此您不必检查整个应用程序(计数,产品列表,推荐产品等)中的产品是否都被软删除。

但是,您可能会在数据仓库模型中考虑“软删除”。 例如。您正在查看已删除产品上的旧收据。*