139

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

这是常见的做法吗?

这安全吗?

4

26 回答 26

81

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

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

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

于 2008-12-18T16:13:53.560 回答
31

逻辑删除是常见的做法吗?是的,我在很多地方都看到过。它们安全吗?这真的取决于它们是否比您删除之前的数据更不安全?

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

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

  1. 保留所有数据的性能影响,我们制定各种归档策略。例如,应用程序的一个领域接近于每周生成大约 1Gb 的数据。
  2. 保存数据的成本确实会随着时间的推移而增加,虽然磁盘空间很便宜,但用于在线和离线保存和管理数 TB 数据的基础设施数量很多。冗余需要大量磁盘,人们需要时间来确保备份快速移动等。

在决定使用逻辑、物理删除或归档时,我会问自己以下问题:

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

可能有点晚了,但我建议大家查看Pinal Dave关于逻辑/软删除的博客文章:

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

在上述情况下,小桌子与大桌子相比有什么优势?

  • 较小的桌子易于维护
  • 索引重建操作更快
  • 将存档数据移动到另一个文件组将减少主文件组的负载(考虑到所有文件组都在不同的系统上)——这也将加快备份速度。
  • 由于尺寸较小,统计信息将经常更新,这将减少资源密集度。
  • 索引的大小会更小
  • 表的性能将随着表大小的减小而提高。
于 2014-09-30T16:42:20.160 回答
18

我是一名 NoSQL 开发人员,在我的上一份工作中,我处理的数据对某人来说总是很重要,如果它在创建的同一天被意外删除,我无法在上次备份中找到它从昨天!在那种情况下,软删除总能化险为夷。

我使用时间戳进行了软删除,记录了文档被删除的日期:

IsDeleted = 20150310  //yyyyMMdd

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

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

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

于 2015-03-11T03:35:41.053 回答
11

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

这允许您“重建”已删除/更改的记录,并且您仍然可以在主表中硬删除并保持“干净” - 它还允许创建“撤消”功能,您还可以记录日期、时间,以及在镜像表中执行操作的用户(在猎巫情况下非常宝贵)。

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

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

还有什么优点?- 如果你有一堆程序员在做这个项目,用混合技能和对细节级别的关注来读取数据库,你不必熬夜希望他们中的一个没有忘记不包括已删除记录(大声笑,不包括已删除记录 = True),这会导致夸大客户可用的现金头寸,然后他们会购买一些股票(即,如在交易系统中),当您使用交易系统时,您将很快发现稳健解决方案的价值,即使它们可能有更多的初始“开销”。

例外:
- 作为指导,对“参考”数据(如用户、类别等)使用软删除,对“事实”类型数据(即事务历史)的镜像表使用硬删除。

于 2016-09-09T00:18:30.090 回答
5

我通常使用逻辑删除 - 我发现当您间歇性地将“已删除”数据归档到归档表(如果需要时可以搜索)因此不会影响应用程序的性能时,它们工作得很好。

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

于 2008-12-18T16:17:50.307 回答
5

我是逻辑删除的忠实拥护者,尤其是对于业务线应用程序或在用户帐户的上下文中。我的理由很简单:很多时候我不希望用户能够再使用系统(因此帐户被标记为已删除),但如果我们删除了用户,我们将失去他们所有的工作等等。

另一个常见的情况是用户可能会在被删除后重新创建一段时间。对于用户来说,让他们的所有数据都像被删除之前一样存在,而不是必须重新创建它,这是一种更好的体验。

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

于 2008-12-18T16:24:50.447 回答
5

我曾经做过软删除,只是为了保留旧记录。我意识到用户并不像我想象的那样频繁地查看旧记录。如果用户想查看旧记录,他们可以从归档或审计表中查看,对吗?那么,软删除有什么好处呢?它只会导致更复杂的查询语句等。

在我决定不再软删除之前,以下是我已经实现的东西:

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

  2. 识别哪些表被认为是“事务表”,很可能会保留很长时间,并且很可能用户可能希望查看过去的记录或报告。例如; 购买交易。该表不应只保留主表的id(如dept-id),还应保留名称作为参考(如dept-name)或任何其他必要的报告字段等附加信息。

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

只是我的两分钱意见。

于 2016-06-06T03:06:04.733 回答
5

我几乎总是软删除,原因如下:

  • 如果客户要求您这样做,您可以恢复已删除的数据。软删除让客户更满意。从备份中恢复特定数据很复杂
  • 检查isdeleted无处不在不是问题,userid无论如何您都必须检查(如果数据库包含来自多个用户的数据)。您可以通过将这两个检查放在单独的函数(或使用视图)上来强制执行代码检查
  • 优雅的删除。处理已删除内容的用户或进程将继续“看到”它,直到他们点击下一次刷新。如果进程正在处理一些突然删除的数据,这是一个非常理想的功能
  • 同步:如果您需要在数据库和移动应用程序之间设计同步机制,您会发现软删除更容易实现
于 2018-06-09T12:44:56.690 回答
4

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

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

如果您的意思是通过执行逻辑删除,您的数据更安全,因为您永远不会丢失任何数据,那也是正确的。这对审计场景有好处;我倾向于这样设计,因为它承认一个基本事实,即一旦生成数据,它就永远不会真正消失(特别是如果它有能力被互联网搜索引擎缓存)。当然,真正的审计场景不仅要求删除是合乎逻辑的,而且还要记录更新,以及更改的时间和进行更改的参与者。

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

于 2008-12-18T16:32:20.993 回答
3

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

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

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

我看到的唯一优点是记录的历史记录,但是还有其他方法可以实现此结果,例如您可以创建一个可以保存信息的日志记录表:可以在TableName,OldValues,NewValues,Date,User,[..]哪里并在此表单中写入详细信息;[..] 或将信息存储为.*Valuesvarcharfieldname : valuexml

所有这一切都可以通过代码或触发器来实现,但您只是一张拥有所有历史记录的表。另一种选择是查看指定的数据库引擎是否原生支持跟踪更改,例如在 SQL Server 数据库上有 SQL Track Data Change。

于 2014-09-30T17:18:20.613 回答
2

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

另一方面,要求可能是,一旦记录被“删除”,它就被真正且不可撤销地删除。在做出决定之前,请与您的利益相关者交谈。

于 2015-02-20T13:03:52.900 回答
2

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

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

否则将数据移动到审计表并删除记录。

从积极的一面:

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

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

于 2008-12-18T16:31:48.297 回答
2

如果您想保留某事的历史记录(例如@Jon Dewees 提到的用户帐户),这是相当标准的。如果用户要求取消删除的可能性很大,这当然是一个好主意。

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

于 2008-12-18T16:34:44.750 回答
2

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

于 2015-07-15T09:10:17.513 回答
1

他们不让数据库执行,因为它应该使诸如级联功能之类的东西变得无用。

对于插入等简单的东西,在重新插入的情况下,那么后面的代码就加倍了。

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

它们会导致性能问题,因为表被冗余数据堵塞。它对索引特别是唯一性进行了破坏。

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

于 2012-07-04T15:47:14.270 回答
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.

后一种逻辑必须使用触发器以编程方式实现或在我的应用程序代码中处理,并且我无法设置检查。

对每个独特的列重复此操作!

我认为这个解决方案真的很hacky,并且会支持一个单独的存档表来存储已删除的行。

于 2020-08-24T10:55:20.823 回答
1

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

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

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

这不仅仅是is_deleted列。您可以随时使用 backref 版本表来检查此条目发生了什么。条目是否被删除、更新或添加。

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

于 2017-09-08T02:54:13.547 回答
0

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

在 EF 6.x 或 EF 7 及更高版本中,Softdelete 被添加为属性,但我们现在必须创建一个自定义属性。

我强烈推荐 SoftDelete 在数据库设计中,它是编程实践的良好约定。

于 2014-11-14T07:40:59.087 回答
0

出色地!正如大家所说,这取决于情况。

如果您在 UserName 或 EmailID 之类的列上有索引 - 您永远不会期望再次使用相同的 UserName 或 EmailID;您可以使用软删除。

也就是说,请始终检查您的 SELECT 操作是否使用主键。如果您的 SELECT 语句使用主键,则在 WHERE 子句中添加标志不会有太大区别。举个例子(伪):

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

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

由于 UserID 列具有主键,因此该查询不会对性能产生任何影响。最初,它会根据 PK 扫描表,然后执行下一个条件。

软删除根本不起作用的情况:

在大多数网站上注册都将 EmailID 作为您的唯一标识。我们非常清楚,一旦在 facebook、G+ 等网站上使用 EmailID,其他任何人都无法使用它。

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

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

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

于 2015-06-20T14:12:50.773 回答
0

大多数时候使用软删除是因为您不想公开某些数据,但由于历史原因您必须保留它(产品可能会停产,因此您不希望与它进行任何新交易,但您仍然需要使用销售交易的历史)。顺便说一句,有些人正在复制销售交易数据中的产品信息值,而不是引用产品来处理这个问题。

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

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

从安全的角度来看,SoftDelete 不会取代 Audit 的工作,也不会取代备份的工作。如果您害怕“两个备份案例之间的插入/删除”,您应该阅读完整或批量恢复模型。我承认 SoftDelete 可以使恢复过程变得更简单。

由您来了解您的要求。

于 2017-09-19T14:34:37.093 回答
0

视情况而定,请考虑以下几点:

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

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

于 2020-01-17T22:17:20.707 回答
0

这完全取决于系统的用例及其数据。

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

但是,也许您的系统及其数据有一个用例,例如“跟踪北极的天气”。也许您每小时读取一次温度读数,并在一天结束时汇总每日平均值。也许在聚合后将不再使用每小时数据,并且您会在创建聚合后硬删除每小时读数。(这是一个虚构的、琐碎的例子。)

关键是,这完全取决于系统的用例及其数据,而不是纯粹从技术角度做出的决定。

于 2018-04-13T19:19:09.083 回答
0

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

所以我们两者都做。我们与客户一起确定他们希望能够恢复数据多长时间。例如,通常客户和产品在我们的客户说应该删除之前是活跃的,但销售历史只保留 13 个月,然后自动删除。客户可能希望将已删除的客户和产品保留两个月,但将历史记录保留六个月。

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

我们关心的不是数据安全,而是在内存有限的客户端设备(例如智能手机)上拥有庞大的数据库。一个连续四年每周两次订购 200 种产品的客户将拥有超过 81,000 条历史记录,其中 75% 的客户不关心他是否看到。

于 2018-02-09T21:35:54.533 回答
0

优点是数据保存/永久化。一个缺点是在从具有大量软删除的表中查询或检索数据时性能下降。

在我们的例子中,我们使用两者的组合:正如其他人在之前的答案中提到的那样,soft-delete users/clients/customers例如,我们在存在不需要保留重复记录hard-delete的表上。items/products/merchandise

于 2019-11-15T18:03:35.660 回答
0

我已经在另一个帖子中回答了。但是,我认为我的回答更适合这里的问题。

我对软删除的实用解决方案是通过创建一个具有以下列的新表来归档:original_id, table_name, payload, (和一个可选的主键 `id)。

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

我还建议在列上建立一个索引,original_id以便以后检索数据。

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

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

这里已经是一个讨论 ,解释了为什么软删除在实践中不是一个好主意。软删除会在将来引入一些潜在的麻烦,例如计数记录,...

于 2019-09-27T02:41:23.097 回答