软删除是个好主意吗? [复制]
Posted
技术标签:
【中文标题】软删除是个好主意吗? [复制]【英文标题】:Are soft deletes a good idea? [duplicate] 【发布时间】:2011-02-02 17:43:07 【问题描述】:软删除是好主意还是坏主意?
您只需将其标记为IsDeleted = true
,而不是实际删除数据库中的记录,在恢复记录后您可以将其标记为False
。
这是个好主意吗?
物理上删除记录,然后将其移动到存档数据库,如果用户想要恢复记录,那么软件将在存档中查找记录并重新创建它是不是更好?
【问题讨论】:
@Brian - 他们使用碎纸机。 使用删除时间戳,而不是标志。 我在一个应用程序上工作,该应用程序在表上使用了IsDeleted
属性。结果是经常出现错误。问题应该很明显:普通用户想要对表运行的每个查询都涉及non-deleted
数据,这意味着涉及该表的99.9% 的查询必须将...AND IsDeleted = 'N'
添加到其WHERE
子句中。自然地,它经常被省略:要么编码人员忘记添加它,要么不知道他们必须首先添加它。当然,在原始规范中并没有这样的要求,编码器正在使用他们的主动性......
@onedaywhen - 您描述的问题可以通过使用VIEW
轻松解决。如果之后添加IsDeleted
,甚至应该可以将原始表重命名,例如将mytable
改为mytable_all
,然后将视图命名为mytable
,并添加另一个名为mytable_deleted
的视图。这样就不需要更改对表的引用。
@blasto:使用审计表和审计列(删除、创建、更新和由谁)来跟踪删除行的原因。根据问题域,了解数据被删除的原因可能并不相关。如果相关,则添加注释列:审计表将跟踪修订历史。
【参考方案1】:
我不会试图“在政治上正确”。如果您提倡软删除,那么您需要进行大脑检查。
1) 首先,通过不删除表中的行,您究竟实现了什么?只是事实是将来某个时候您可以访问这些行,对吗?那么为什么不直接创建一个存档表并将行移到那里呢?这有什么问题?
2) 使用软删除,您将在 is_active 上创建不必要的查询或在某些时间戳列上进行查询。当您编写更简单的查询时,这只是浪费。是的,它可以与视图一起使用,但视图不是额外的附属物吗?每个视图都是一个额外的 SQL,额外的性能成本,在任何商业 RDBMS 中,一切都只是一个表。除了您不知道如何在表之上编写查询之外,视图并没有什么神奇之处。
3) 是的,它适用于视图或 MV。但是后来我看到生产中的查询在做 FTS 并且一切仍然有效!现代硬件和可靠软件的奇迹。但这也不是正确的。所以按照同样的逻辑,仅仅因为它有效并不意味着它是正确的
4) 软删除的复杂性永远不会停留在简单的选择上。
A) 假设您有一个 UNIQUE 约束。现在您软删除了一行,但具有 UNIQUE 约束的列仍然存在。当您想重新添加相同的数据时,如果没有额外的“技巧”,您将无法做到这一点。
B) 您可能有从表 A 到表 B 的关联,当您从表 A 中软删除某些内容时,您需要确保表 B 上的独立查询处理该事实。假设一个典型的详细信息页面正在处理某个 detail_id。
现在 master_id 已被软删除,但您仍然有带有该 master_id 的 detail_id 的永久链接。当您对 master_id 进行硬删除时,这些详细信息根本不存在。现在,通过软删除,它们仍然存在,并且它们必须知道它们的 master_id 处于软删除模式这一事实。
它不会停留在简单的 Table_A.is_active = 0 或 1 阶段。
5) 进行硬删除既简单又正确。
A) 没有人需要在任何地方添加任何额外的内容或担心任何事情。
-
你的应用逻辑更简单
您的数据库较小
您的查询速度更快
只需归档数据+相关部分,你应该会很好。
【讨论】:
这是一个非常假设性的答案。如果没有每种情况的所有详细信息,您怎么能得出绝对没有任何理由使用软删除的结论?永远不要把话说绝了。这表明你缺乏想象力。 并且不分享您的详细信息 - 您不是在做假设吗?软删除不好,我坚持我的说法。分享你的案例,我会指出你的缺陷。 嗯,我想说这个页面上的普遍共识表明你是孤独的。这里的人们不仅记录了可能使用它的不同场景,而且还记录了使其有用的实用方法。如果您选择建议所有这些人都需要进行“大脑检查”,那是您的特权,它会反映在您身上。 硬删除不是唯一的方法。在某些情况下,您不能只硬删除记录。有时我需要引用已删除记录(链接在另一个表中),即使它已被删除,这是通过软删除来完成的。将“存档表”中的记录移动并没有您描述的那么简单,它不会停留在从a到b的简单移动。 在某一时刻,普遍的共识是太阳绕着地球转,人们会因为不这样说而被烧死。如果您真的认为软删除是一个好主意,那么您在一段时间内没有管理任何复杂的数据库。无论您试图通过执行软删除来实现什么,都可以以一种干净的方式在没有软删除的情况下实现。到目前为止,人们只是抱怨自己推定,但没有人提供任何数据。软删除是对归档问题的惰性解决方案。如果您不需要,为什么该表中的数据会挂起?【参考方案2】:在oracle中,如果将主键添加到您组成的recycle_bin表中,然后添加行级安全策略,您可以在该行在回收站中时抑制所有查询的值,从回收站会自动恢复所有数据。无需更改其他查询以适应逻辑。
【讨论】:
这是一个非常有趣的功能,谢谢。【参考方案3】:我说这是一个坏主意,一般来说(也许有一些例外)。
首先,您的数据库应该定期备份,因此您永远不会因为删除而永久丢失数据(当然,除非是删除刚刚添加的数据)。
其次,像这样的软删除意味着您现在必须在此表的每个查询中包含一个WHERE IsDeleted = false
子句(如果您要加入这些表,情况会更糟)。一旦用户或测试人员注意到再次出现已删除的记录,就会发现这里的错误,这可能需要一些时间。此外,开发人员很容易从 COUNT(*) 查询中省略 WHERE 子句,这可能需要更长的时间才能发现(我从事的一个项目已经发生了多年;没有多少记录被“删除” ,所以总数接近预期,没有人注意到)。
最后,软删除将适用于具有人工键的表,但可能不适用于具有自然主键的表(例如,您从以社会保险号为键的表中“删除”某人 - 您会怎么做?什么时候需要把他加回来?请不要说“在复合主键中包含 IsDeleted”。)。
在设计审查中,我希望开发人员能够展示对成本和收益的认识,并提出以这种方式进行软删除的极好的理由。 “为什么不这样做?”不是一个很好的理由。
【讨论】:
创建一个视图并在需要时实现它是相当简单的,它排除了所有 is_deleted 记录。然后可以针对视图运行所有查询。至于从备份中恢复——比如重新启用用户帐户——你真的不想跑到档案中来恢复他们的数据。您想设置 is_deleted = false。这是一个相当原始(并且不太可能)的场景,因为您可能会使用禁用的字段 - 但要点是相同的。在某些情况下,能够立即恢复已删除的数据可能是值得的。 @Josh:SQL 编程中的一切都相当琐碎;许多琐碎的事情的积累开始导致问题。正如我在上一句中所说,我希望开发人员有充分的理由以这种方式增加系统的复杂性。看到这么多开发人员说他们这样做是理所当然的,不管他们的应用程序的实际需求如何,我感到很失望,但一点也不感到惊讶。 @TravisJ 在大多数情况下,我不再同意软删除的概念。我认为“以防万一”不是软删除的好理由。 另外值得一提的是:UNIQUE
索引与软删除相结合会造成混乱。例如。尝试注册已删除的用户名会失败,即使它没有被使用。
+1 表示不使用软删除,除非你真的有理由这样做。这里没有提到的是参照完整性停止以正确的方式处理软删除的行。如果将行标记为已删除,则应将每个子行也标记为已删除,如果不这样做,DBMS 将不会阻止此类逻辑删除。所以“级联删除没有问题”不是这里的情况。那你为什么不删除整个FK呢?它还允许您在不检查引用记录的情况下删除行。【参考方案4】:
如果您要使用软删除,最好使用 deleted_date 字段,而不是 is_deleted 字段。你会得到一个很好的额外数据,而不仅仅是位字段。
【讨论】:
+1 用于使用 DateTime 字段而不是 Bits...我必须使用“IsSomething”和“DateSomethinged”管理的旧系统数量非常高... 我们最近被要求在表中直接创建 isDeleted 位作为列...要求对其值进行管理。我们之前在视图中有这个位,是根据 deleteDate IS NOT NULL 和 deleteDate @BrandonWittwer,为什么?如果你有一个first_name
列和一个last_name
列,你是否也会有一个full_name
列,只是因为应用程序需要一个full_name
属性,还是你会在应用程序中计算它?顺便说一句,deleteDate < Getdate()
应该是多余的。此外,在不了解您的后端的情况下,也许您可以实现一个计算列,这样您就不必自己管理维护两个单独列的完整性。 technet.microsoft.com/en-us/library/ms191250(v=sql.105).aspx
@JoshSmeaton,你准确地描述了我的挫败感。可以完全由同一记录中的其他数据构成的数据绝对应该是视图的一部分。如果实现很重要(作为性能考虑),可以考虑计算列。当然,在这种情况下,计算是不可能的,因为那里的 getDate()...非确定性的。
从技术上讲 SomeStatusesDateField
【参考方案5】:
只是为了加一分钱。我总是软删除;虽然它确实花费了性能,但非常轻微。考虑一下成本,当您的客户抱怨您的软件在她执行某些甚至她不记得的操作后停止运行时。好吧,这可能是一个胖例子,但你永远不会知道出了什么问题,谁做了什么,之前是什么,之后插入了什么。在这种情况下,这将派上用场。此功能可方便地用于审计目的,许多客户要求此类审计报告。
此外,在大多数基于工作流的应用程序中,客户对在工作项上执行的“操作”感兴趣的软件功能/要求;分配了哪些值以及谁处理了它等。
【讨论】:
这正是它不起作用的原因。您假设每个操作都是插入。但是更新呢?他们不会被审计,你也看不到谁以这种方式执行了更新或插入。软删除是一种廉价(且功能失调)的方式,无需投入工作即可构建有效的修订控制。【参考方案6】:我遇到了以下广泛场景的软删除:
案例 1:删除用户/代码可见的记录,但将记录保留在数据库级别,因为企业有兴趣知道它有这些记录。 这些要求主要由业务驱动,通常核心可能是法律要求(如@joshperry 和@armandino 场景),在数据库中拥有先前的记录并为每次更改创建新记录。在这一点上,我会查看 CASE 2 并评估它是否满足要求,然后再设置 IsDeleted 标志
案例 2:跟踪记录演变的审计跟踪 - 网上有大量不错的文章可用于在数据库中保存记录的审计跟踪
HTH。
【讨论】:
【参考方案7】:我是软删除的粉丝。主要是为了防止级联删除。但是,它需要额外的代码,因此如果您正在选择一个子对象,它会连接到父对象(以及所有父对象!)以确保它们都不会被删除。或者,您可以级联软删除,但如果您想稍后恢复它们,您可能不知道哪些子级已被删除,哪些因级联而被删除。
此外,我在每个对象上保留了修订日期时间和修订用户名,以便我知道谁最后修改(或软删除)它。然后,对于审计跟踪,我创建了一个 *History(如 CustomerHistory)表,该表在每次 UPDATE 后插入到原始表中。这样,在修改或软删除对象后,我可以记录执行操作的人员以及对象的最后已知状态。
【讨论】:
通过取消选中“CASCADE DELETES”框(或者在您选择的数据库中完成)防止级联删除不是更容易吗?【参考方案8】:有时需要软删除。例如,假设您有一个引用 Products 表的 Invoice 表。使用特定产品创建发票后,您将永远无法删除该产品(如果您的 RI 设置正确,它不会让您删除)。
此特定场景假定您永远不想删除发票,而在真实公司中您可能不想删除历史财务数据。
尽管在许多其他情况下,您将无法删除某些数据,这是由于业务或其他原因导致链上依赖项无法删除的副作用。
【讨论】:
这不是“暂停”而不是“删除”吗?因此,我认为当您需要历史数据时“暂停”记录是合适的,而当您不需要历史数据(或意味着轻松撤消删除)时,“删除”记录是合适的。 非常正确。我根据实际实现来推销这个想法,并可能将字段命名为“hidden_on”(时间戳)和“hidden_by”(用户 ID)。这是因为记录应该对最终用户隐藏,而不是对管理员隐藏。对于管理,所有记录仍必须照常可见,除非对用户“隐藏”(删除)的记录将被标记为管理员。如果我的数据库中的每个标准表都有一个存档表,那么我的模式将是原来的两倍。哎呀。【参考方案9】:软删除还允许您从应用程序使用的数据库帐户获得revokeDELETE
权限。
【讨论】:
sigh 应用程序使用的数据库帐户?那会很可爱。 除了人为错误之外,它对任何事情都没有用。如果我是恶意用户并获得访问权限,我仍然可以通过UPDATE table SET Field1 = 0, Field2 = 0, ... WHERE 1
“删除”它们【参考方案10】:
这取决于数据。由于法律/审计要求,某些数据无法删除。
另一方面,社交网站应该提供删除包含所有相关数据(包括联系信息、照片、消息等)的帐户的选项。如果他们不这样做,那就太麻烦了,例如脸书。
【讨论】:
由于法律要求,必须删除一些数据。 好点。还没想到那个。 并且由于非法要求必须删除一些数据。 :)【参考方案11】:软删除的主要问题之一是那些不需要的数据可能会影响数据库性能。几年前,我的一位客户要求我对所有数据库项目进行软删除,我的解决方案是将所有“已删除”项目移动到备份表中,而不是将其保留到当前运行的表中。
【讨论】:
+1 用于将数据移动到另一个表! 您可以改为通过“IsDeleted”对表进行分区,以减轻对性能的影响,如果可以在您的数据库中这样做的话。那么你就不用担心两个不同的表了。【参考方案12】:不过,这是有代价的,因为您需要更新查询和索引才能排除已删除的行。
也许不是切换标志,而是将其移动到另一个“垃圾桶”表。
另外,可以说这只是部分解决方案,因为它仅涵盖删除,但是当您更新一行时,您仍然会覆盖旧值。
一般来说,我会说永远不要删除任何东西,除非你真的必须这样做。这些天磁盘空间很便宜。当然,有一些限制,有些数据是您在法律上必须删除的,有些数据实际上并不那么重要,也许您不需要将旧数据在线保存在同一个表中(某个地方的存档)也可以)。
【讨论】:
【参考方案13】:视情况而定。我可以看到法律要求您真正删除某些内容的情况。也许有人要求从您的系统中永久删除他们的社会安全号码。或者,也许您有一条重复的记录,您想将其合并为一条记录。用已删除的标志保留重复项可能没有好处。
还有一个技术缺点:您不能进行级联删除,这会自动清除对已删除数据的任何引用,以防止外键违规。这不一定是一个大问题,但需要牢记。
否则,我认为这是个好主意。
【讨论】:
好点re:级联删除。 @UpTheCreek:我认为 DanM 的观点是,如果您要进行软删除,则必须自己处理级联删除。如果您使用的是硬删除(我称之为“正常”),您可以让数据库自动执行级联删除。 @MusiGenesis - 那么级联恢复呢? +1 表示以“取决于..”开头【参考方案14】:如果无效删除绝对是灾难性的并且恢复应该很简单,这是一个好主意。如果您想跟踪曾经存在的所有内容,并且“删除”实际上仅意味着“隐藏”,这也是一个好主意。意思是,视情况而定。
【讨论】:
【参考方案15】:避免潜在的数据丢失绝不是一个坏主意。
我总是软删除。在需要清除数据库中的一条或多条记录的情况下,我通常采用软删除的两步过程,然后清空记录的“回收站”,或者采用文档管理风格的方法,其中文档记录可以被老化,然后在硬删除之前通过审批流程。
【讨论】:
系统通常仍需要数据用于完整性、审计或更改历史...软删除!使用清理过程进行真正的删除等... PK :-) +1:I always soft-delete.
因此您不必在每个查询中检查 where deleted=0,您可以为为您执行此操作的表创建一个视图。然后,您可以创建一个名为 recycle_bin 或类似的视图,仅显示已删除的记录(对对其公共字段进行软删除的表进行联合)
+1 用于使用安全、混合、两步流程
如何处理软删除数据的关系?例如,您删除了company_departments
表中的一条记录。然后你有users
表,那里有一个FK department_id
。在这种情况下,您是否会更新 users 表并将 department_id
FK 设置为 null 以匹配软删除部门?以上是关于软删除是个好主意吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为程序使用不同的 Python 脚本是个好主意吗? [关闭]