关于sql:数据库记录的物理与逻辑/软删除?

Physical vs. logical / soft delete of database record?

与实际或实际删除记录相比,逻辑/软删除记录(即设置一个声明记录已删除的标志)有什么好处?

这是惯例吗?

这个安全吗?


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

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

编辑:考虑到另一个不利因素-如果表上有唯一索引,则删除的记录仍将占用"一"记录,因此您也必须对此可能性进行编码(例如,用户名上有唯一索引的用户表;删除的记录仍将阻止新记录的删除用户用户名。解决这个问题,您可以将一个guid附加到已删除的用户名列,但这是一个非常简单的解决方法,我不推荐。在这种情况下,最好有一个规则,即一旦使用了用户名,就永远不能替换它。)


逻辑删除是常见的做法吗?是的,我在很多地方都见过。它们安全吗?这真的取决于它们的安全性是否比删除数据前差了一些?

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

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

  • 保留所有数据对性能的影响,我们要制定各种归档策略。例如,应用程序的一个领域接近于每周生成大约1GB的数据。
  • 保存数据的成本随着时间的推移而增长,尽管磁盘空间很便宜,但是在线和离线保存和管理数兆字节数据的基础设施数量却很大。它需要大量的磁盘来实现冗余,人们需要时间来确保备份快速移动等等。
  • 当决定使用逻辑、物理删除或存档时,我会问自己以下问题:

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

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

    I just do not like this kind of design [soft delete] at all. I am firm believer of the architecture where only necessary data should be in single table and the useless data should be moved to an archived table. Instead of following the isDeleted column, I suggest the usage of two different tables: one with orders and another with deleted orders. In that case, you will have to maintain both the table, but in reality, it is very easy to maintain. When you write UPDATE statement to the isDeleted column, write INSERT INTO another table and DELETE it from original table. If the situation is of rollback, write another INSERT INTO and DELETE in reverse order. If you are worried about a failed transaction, wrap this code in TRANSACTION.

    What are the advantages of the smaller table verses larger table in above described situations?

    • A smaller table is easy to maintain
    • Index Rebuild operations are much faster
    • Moving the archive data to another filegroup will reduce the load of primary filegroup (considering that all filegroups are on different system) – this will also speed up the backup as well.
    • Statistics will be frequently updated due to smaller size and this will be less resource intensive.
    • Size of the index will be smaller
    • Performance of the table will improve with a smaller table size.


    我是NoSQL开发人员,在我的上一份工作中,我处理的数据总是对某个人至关重要的,如果在创建的同一天意外删除了它,我就无法在昨天的最后一次备份中找到它!在这种情况下,软删除总是会保存一天。

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

    1
    IsDeleted = 20150310  //yyyyMMdd

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

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

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


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

    这允许您"重建"已删除/更改的记录,您仍然可以在主表中硬删除并保持其"干净"-它还允许创建"撤消"功能,您还可以在镜像表中记录执行该操作的日期、时间和用户(在witch hunt sit中非常有用行动)。

    另一个优点是,在查询主记录时不可能意外地包括已删除的记录,除非您故意陷入从镜像表中包括记录的麻烦中(您可能希望显示活动和已删除的记录)。

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

    还有什么好处?-很好,如果你有一帮编码员在项目中工作,在数据库中阅读的技巧和对细节的关注程度参差不齐,你不必熬夜希望他们中的一个不会忘记不包括已删除的记录(lol,不包括已删除的记录=true),结果是在夸大的情况下,比如说客户的可用现金头寸,然后他们购买一些股票(例如,在交易系统中),当你使用交易系统时,你会很快发现强大解决方案的价值,即使它们可能有一点更多的初始"开销"。"。

    例外情况:-作为指南,对"引用"数据(如用户、类别等)使用软删除,对"事实"类型数据(即事务历史)的镜像表使用硬删除。


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

    • 如果客户要求,您可以恢复删除的数据。使用软删除的客户更满意。从备份中恢复特定数据很复杂
    • 在任何地方检查isdeleted都不是问题,您无论如何都必须检查userid(如果数据库包含多个用户的数据)。通过将这两个检查放在单独的函数(或使用视图)上,可以通过代码强制执行检查。
    • 优雅删除。处理已删除内容的用户或进程将继续"查看"该内容,直到单击下一次刷新。如果一个进程正在处理一些突然被删除的数据,这是一个非常理想的特性。
    • 同步:如果你需要设计一个数据库和移动应用程序之间的同步机制,你会发现软删除更容易实现。


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

    它工作得很好,因为如果你被审计过,你仍然有数据。如果你物理删除了它,它就不见了!


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

    另一个常见的场景是,删除后用户可能会被重新创建一段时间。对于用户来说,像删除数据之前一样呈现所有数据,而不是重新创建数据,这是一种更好的体验。

    我通常认为删除用户更多的是无限期地"挂起"他们。你永远不知道他们什么时候会回来。


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

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

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

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


    系统设计之外还有一些需求需要回答。记录保留的法律或法定要求是什么?根据与行相关的内容,可能有一个法律要求,即在数据"挂起"后将其保留一段时间。

    另一方面,要求可能是一旦记录被"删除",它将被真正地、不可撤销地删除。在你做出决定之前,先和你的利益相关者谈谈。


    逻辑删除如果在参照完整性上是困难的。

    当表数据存在时间方面时(从"日期"到"日期"有效),这是正确的做法。

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

    有利方面:

    这是一种更容易回滚的方法(如果可能的话)。

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


    如果您想保存某个东西的历史记录(例如@jon dewees提到的用户帐户),这是相当标准的。如果用户有很大的机会要求取消删除,这当然是个好主意。

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


    我强烈反对逻辑删除,因为您会遇到许多错误。

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

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

    我看到的唯一优势是记录的历史记录,但是还有其他方法可以实现这个结果,例如,您可以创建一个日志表,在其中可以保存信息:TableName,OldValues,NewValues,Date,User,[..]在哪里*Values呢??可以是varchar,也可以是fieldname : value、〔….〕的形式填写,也可以存储为xml

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


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


    我以前做软删除,只是为了保留旧记录。我意识到用户不会像我想象的那样经常查看旧记录。如果用户想查看旧记录,他们只能从存档或审核表中查看,对吗?那么,软删除的优点是什么?它只会导致更复杂的查询语句等。

    以下是我在决定不再软删除之前实现的内容:

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

  • 确定哪些表被视为"事务表",这些表很可能会被保存很长时间,并且很可能用户希望查看过去的记录或报告。例如,采购交易。此表不仅要保留主表的ID(如部门ID),还要保留附加的信息,如名称作为引用(如部门名称),或任何其他需要报告的字段。

  • 执行主表的"活动/不活动"或"启用/禁用"或"隐藏/显示"记录。因此,用户可以禁用/停用主记录,而不是删除记录。这样更安全。

  • 只是我的意见。


    它们不允许数据库按照应该的方式运行,因此级联功能是无用的。

    对于插入之类的简单事情,在重新插入的情况下,它后面的代码会加倍。

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

    它们会导致性能问题,因为表中有多余的数据。它对索引尤其是唯一性起着破坏作用。

    我不喜欢逻辑删除。


    为了回应Tohid的评论,我们面临着同样的问题,我们想要保存记录的历史,也不确定是否需要is_deleted列。

    我正在讨论我们的Python实现和我们遇到的类似用例。

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

    这不仅仅是用于is_deleted列。您可以始终回退版本表以检查此条目发生了什么。条目是否被删除、更新或添加。

    这样我们就完全不需要is_deleted列,而且我们的删除功能非常简单。这样,我们也不需要记住在任何API中标记is_deleted=False


    好!正如大家所说,这取决于形势。

    如果您在一个列上有一个索引,比如用户名或emailid,并且您永远不会期望再次使用相同的用户名或emailid;您可以使用软删除。

    也就是说,始终检查选择操作是否使用主键。如果您的select语句使用主键,那么添加带有where子句的标志就不会有太大的区别。让我们举个例子(伪):

    表用户(userid[主键]、emailid、isDeleted)

    1
    SELECT * FROM Users WHERE UserID = 123456 AND IsDeleted = 0

    这个查询在性能方面不会有任何区别,因为userid列有一个主键。最初,它将基于pk扫描表,然后执行下一个条件。

    软删除根本无法工作的情况:

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

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

    是的,在我们有很多外国桌子的情况下,处理起来相当麻烦。

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


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

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

    这种实践是非常常见的模式,许多应用程序使用它的原因很多。因为这不是实现这一目标的唯一途径,所以你会有成千上万的人说这是好事或胡说八道,而且他们都有很好的论据。

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

    由你来决定你的要求。


    为了提供另一种选择,我们让用户通过mobilink使用远程设备更新。如果我们删除服务器数据库中的记录,那么这些记录在客户机数据库中永远不会被标记为删除。

    所以我们都这么做。我们与客户一起确定他们希望能够恢复数据的时间。例如,一般来说,客户和产品都是活跃的,直到我们的客户说应该删除它们为止,但是销售历史记录只保留13个月,然后自动删除。客户可能希望将删除的客户和产品保留两个月,但将历史记录保留六个月。

    因此,我们在夜间运行一个脚本,根据这些参数标记逻辑删除的内容,然后在2/6个月后,今天标记逻辑删除的内容将被硬删除。

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


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

    例如,如果你谈论的是政府管制的系统(例如,制药公司的系统被视为质量体系的一部分,必须遵守FDA电子记录指南),那么你最好不要硬删除!食品和药物管理局的审核员可以进来询问与ABC-123号产品有关的系统中的所有记录,所有数据最好都能得到。如果您的业务流程负责人说系统不应允许任何人在今后的新记录中使用产品编号ABC-123,请使用软删除方法使其在系统中处于"非活动"状态,同时仍保留历史数据。

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

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


    软删除是一种编程实践,当数据更相关时,大多数应用程序都会遵循这种实践。考虑一个财务应用程序的情况,其中由于最终用户的错误而删除可能是致命的。这就是软删除变得相关的情况。在软删除中,用户实际上并不是从记录中删除数据,而是将其标记为删除为真(按正常约定)。

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

    我强烈建议在数据库设计中使用SoftDelete,这对于编程实践是一个很好的约定。