【问题标题】:Should I delete or disable a row in a relational database?我应该删除还是禁用关系数据库中的一行?
【发布时间】:2010-09-25 17:15:24
【问题描述】:

在一个全新的程序中,空间并不是那么重要,是删除一行还是禁用一行更好,让我们说一个布尔值“已禁用”并让程序忽略它?

例如,如果我想从程序中删除用户。

【问题讨论】:

    标签: mysql sql oracle relational


    【解决方案1】:

    不删除将为所有未来的查询创建一类新的错误。不要忘记查询编写通常由高级用户(即非 IT 专业人员)和初级开发人员完成。因此,现在每个具有仅由 BIT 活动标志标记的无效数据的表都需要在 WHERE 子句中为从现在到永远的每个查询添加一个额外的 AND。这将帮助用户陷入失败的深坑,而不是成功的深渊。但是,无论如何,我强烈建议您实现这些标志系统,因为如果没有糟糕的设计,维护开发人员就无需修复它将产生的大量错误。

    在表格中包含历史数据的价值有多大?如果业务具有前瞻性,那么表中的旧数据可能只是一种负担——它在创建约束时会导致问题(必须修改所有约束以排除您希望不存在的数据)。由于必须不断重新识别“我们害怕删除但再也不想使用或更新的旧垃圾”以及我们关心的新内容,数据质量保证变得复杂。

    是否因为错误而被删除?如果该行对应于现实生活中的一个实体,那么保留并设置一个“蒸发”、“死亡”、“离开建筑物”标志可能会很有趣。如果您不小心插入了与现实生活中没有实体对应的行,则 DELETE 并不是一件坏事。将从未存在的假想客户保留在客户表中是否重要?

    最后,个性起着重要作用。人们也可以成为数据的打包者。如果 DBA 保留 30 年前的所有报纸并且不喜欢删除数据,那么也许他应该确保根据优点而不是无关的个人偏好做出数据设计决策。

    【讨论】:

    • 如果高级用户开发查询存在潜在问题,可以围绕表创建一个视图,自动过滤掉“已删除”行。我认为,这甚至算不上一个小问题。
    【解决方案2】:

    这取决于。 (但你已经猜到了,我敢肯定。)

    在实践中,这里违反正确用法的行为几乎总是朝着删除的方向发展。

    删除的主要不良后果是,当父记录消失时,其他表中存在引用完整性丢失的依赖记录的频率。

    一个用来保护删除的红鲱鱼(您已经通过忽略存储容量问题正确处理了它),预计它将对查询效率产生任何明显的影响。

    在很多情况下,用户或软件问题导致某人需要点击“撤消”大按钮;如果你删除了,那你就不走运了(至少没有得到特别的帮助,也没有激怒你喜欢善待的人。)

    我常用的术语是“活跃”和“不活跃”。


    还有几点需要考虑(Totophil):

    1. 删除某些数据库中的记录不会自动释放磁盘空间。
    2. 清除您不再需要的任何敏感信息有助于避免安全风险。
    3. 数据保护立法可能要求您的组织在某些情况下清除有关个人的任何可识别信息。立法因国家而异,一些指针:

    4. 另一方面,法律可能要求您保留某些信息。

    【讨论】:

    • 我通常使用的术语是“Active”和“Inactive”...我几乎总是将其作为额外字段添加到具有主键的表中。作为布尔值,它占用最小的空间,并允许适当的数据完整性,同时为应用程序提供感知删除。唯一麻烦的情况是意外插入,然后立即删除。
    【解决方案3】:

    在阅读了一本关于时间数据库设计的书后,我开始相信每条具有时间意义的记录都需要至少有 4 个时间戳列的理念。这四个是:创建,删除,开始,结束。创建和删除的时间戳是不言自明的。您的系统不应查看在 now() 之前已删除的记录。开始和结束列确定数据何时应用于您的系统。这是为了保留更改的历史记录。如果您需要更新记录,请将其结束时间设置为 now(),复制它,更新副本,并将副本的开始时间设置为 now()。这样,当您需要查看历史上某事的方式时,您可以让系统弄清楚。您还可以将开始时间设置为将来的某个时间点,以便在那时自动进行更改,或者将结束时间设置为将来的时间以使其在那时自动消失。将创建/删除的时间戳设置为未来并没有什么意义......

    【讨论】:

    • 哪本书?看起来很有趣。
    • 我一直发现将这种历史数据放在单独的数据仓库中会更好。所有这些历史数据都会拖慢一张大表的爬行速度。此外,如果您在表上进行大量插入,则数据库需要不断移动数据以保持聚集索引的组织性。
    【解决方案4】:

    如果您确实使用了已删除、可见、已激活等列,您可以通过使用视图来抽象出必须记住使用它的情况。

    【讨论】:

      【解决方案5】:

      这取决于您和您的要求(当存在记录时,有些事情会变得相当困难......不要)。

      不过,我会说布尔值是一个糟糕的选择。使其成为可为空的时间戳。知道何时删除某些内容非常方便,尤其是当您删除太多并想要撤消部分删除时。

      【讨论】:

        【解决方案6】:

        这取决于。如果它被禁用,那么更容易取消删除/看到有人实际删除了记录(用于审计)。

        您可能还有不删除记录的技术要求。例如,如果您想通过仅发送更改的记录来与其他用户同步数据库,那么如果它被实际删除,您将无法做到这一点。

        【讨论】:

          【解决方案7】:

          你需要在功能需求中有它。如果没有明确说明,您将不得不自己弄清楚。

          在大多数情况下,最好将此类记录存储在单独的表中。然后,您可以避免一个表引用另一个表的各种情况,您需要决定是否应该将第二个表中的记录也视为已删除。

          【讨论】:

            【解决方案8】:

            在您的表中添加“已删除”列并标记行而不是删除它们会为您带来更多的工作,而几乎没有(如果有的话)收益。现在,每次编写查询时都必须记住包含“WHERE DELETED IS NOT NULL”(或其他)。

            更好的方法是在您需要删除数据时删除数据,并依靠您的定期备份过程来确保不会丢失任何数据。如果出于某种原因您需要将一些已删除的数据放在手边(可能是为了搜索),您最好将数据复制到为此目的创建的不同表中,然后删除原始数据。

            多年来,我继承了许多数据库,不幸的是,这种标记记录而不是删除记录的策略非常普遍,而且(至少根据我的经验)总是会导致未来出现重大问题。

            【讨论】:

            • 我相信这将是 Deleted != 'Y' 或 Deleted = 'N' 或类似的,而不是空值。此时视图可能会有所帮助。
            【解决方案9】:

            如果您有时需要删除的数据,但不是很频繁:您可以将记录移动到单独的数据库中/table(例如usersusers_deleted,或者更好的somedb.userssomedb_deleted.users)。

            这样,数据仍然可以通过查询访问(尽管它不会像普通查询那样简单),但它不会使原始数据库混乱,您也不必围绕它编写代码。

            【讨论】:

              【解决方案10】:

              除非您特别需要管理自己的删除,否则最好只删除行。

              【讨论】:

                【解决方案11】:

                我想指出,(在大多数国家/地区)存在出于法律原因无法删除记录的用例。当然取决于行业和数据。

                在这种情况下,我认为最佳实践指南是将“已删除”数据映射到表中,这将为您带来实际删除 outlined by MatthewMartin 的好处,并且通过扩展,我发现这种模式通常比创建“活动”位更可取- 我的数据表中的标志。

                【讨论】:

                  【解决方案12】:

                  这应该由应用程序的需要来决定。我已经做到了两种方式。我有一些应用程序需要支持撤消,因为删除一行的成本——以及由此引起的级联删除——太昂贵了,不能拥有它。不过,通常情况下,我所做的应用程序要求用户确认删除,然后按照用户的要求进行操作。在某些情况下,出于隐私考虑,您必须删除数据。也就是说,如果用户请求删除,您需要真正删除它,而不仅仅是将其标记为非当前。在其他情况下(例如与税务相关的交易),可能有理由将数据保持在非当前状态,直到法律不再要求。我有适合这两个类别的应用程序。

                  在您需要保留“存档”数据的情况下,可以使用各种策略。根据它是否需要立即可用,您可以将其推送到存档表,这些表要么被保留,要么被定期备份和清理。如果需要撤消,您可能希望将其保留在当前表中并通过设置标志来标记它。这实际上取决于您的架构的复杂性、应用程序的要求以及在某种程度上的个人偏好。

                  【讨论】:

                    【解决方案13】:

                    我正在创建一个 CRUD,我也面临同样的问题。

                    解决方案:CRUD 的 D 应该禁用而不是删除。

                    问题:

                    • “Every”查询应该检查注册表是否被禁用(例如 flag=1)。更具体地说,选择 * 应该检查这一点。
                    • 默认情况下,每次插入都应激活注册表(标志=1)。
                    • 更新不应更改标志。
                    • Disable 是一个变相的更新,它标记了 flag=0。

                    大问题

                    • 垃圾收集器。存在三种策略:删除旧注册表、删除未引用的注册表或混合策略。

                    【讨论】:

                      【解决方案14】:

                      这是一个判断调用,但我最终在我以前认为可以删除行的表上添加了“禁用”列。我会说大多数时候添加禁用列会更安全。但是,这对于 n:n 关系可能会变得棘手,因此需要考虑。

                      【讨论】:

                      • 联结记录有多棘手?我认为同样的逻辑适用于关系和实体。
                      • 因为这两条记录之间的关系本身可以被“删除”,表明它们不再相关但曾经相关。现在,如果有人想重新添加关系怎么办?这可能不是所有应用程序的问题。
                      【解决方案15】:

                      最好添加“已删除”列并让用户取消删除或清除已删除的项目。

                      【讨论】:

                        【解决方案16】:

                        这取决于数据库的功能。它是所有真相的来源吗?如果是,则禁用而不是删除,因为更容易从错误操作(即用户错误)中恢复。如果数据库来自某些上游数据源,则删除未使用的数据。上游系统可以完成任何娱乐/恢复。

                        【讨论】:

                          【解决方案17】:

                          正如许多人已经说过的,应用程序的需求决定了您想要做什么。但对我来说,标记一行似乎没有为正确的事情使用正确的工具。从逻辑上讲,我们将删除视为 DELETE,因此,如果出于法律原因不允许删除,则首先不要删除它。 同时,我考虑了所有内部数据结构的保存和索引。更不用说可以为检索数据进行的所有优化,但添加该检查(在视图或查询中)会随着数据库的复杂性和实体之间的关系成倍地影响性能。

                          简而言之,将删除逻辑放在 UI 层,以防止用户出错,并将删除权限授予应该能够删除它的用户。使用定期备份来保存档案。如果您的应用程序绝对需要严格的审计历史记录,请在触发器中实现它并将审计放在一个异地数据库中,以避免生产中的所有流量、检查和废话。

                          【讨论】:

                            【解决方案18】:

                            对此我常用的另外两种解决方案。我同意其他人的观点,认为这确实符合您的数据要求。

                            如果使用外键约束会导致引用完整性问题,您可以阻止用户删除记录(前提是您的 RDBMS 支持)。有几次我向最终用户提供了一条消息:“在解除 与它的关联之前,您无法删除此 。”只要您没有预料到与其他一个或多个表的关联数量不会非常多,这种方法就可以工作。

                            另一种方法是将任何已取消关联的记录移动到与未删除的记录相关联。例如,假设您有一门课程,其中关联了 10 个单独的上课时间。如果您删除课程,您可以允许用户决定是否删除所有 10 个课程,或者它们是否与新课程或现有课程相关联。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2011-08-12
                              • 2016-06-09
                              • 1970-01-01
                              • 1970-01-01
                              • 2017-08-09
                              • 1970-01-01
                              • 1970-01-01
                              • 2019-12-06
                              相关资源
                              最近更新 更多