相较于实际或物理删除记录,逻辑/软删除记录的优点是什么(即设置标志表示记录已删除)?
这种做法常见吗?
这样做安全吗?
相较于实际或物理删除记录,逻辑/软删除记录的优点是什么(即设置标志表示记录已删除)?
这种做法常见吗?
这样做安全吗?
TableName,OldValues,NewValues,Date,User [..]
,其中*Values
可以是varchar
类型,并以以下形式编写详细信息fieldname : value
; [..]或将信息存储为xml
。如果逻辑删除对参照完整性造成困难,就需要慎重考虑。
当表数据存在时间方面的因素(有效FROM_DATE - TO_DATE)时,逻辑删除是正确的选择。
否则,将数据移动到审计表中并删除记录。
优点是:
这是回滚的简单方式(如果可能的话)。
可以轻松查看特定时间点的状态。
除了系统设计之外,还有其他需求需要回答。在记录保留方面,法律或法规要求是什么?根据行与何相关,可能存在法律要求在“暂停”后的一定时间内保留数据。
另一方面,要求可能是一旦记录被“删除”,它就真正且不可撤销地被删除。在做出决定之前,请与您的利益相关者进行交流。
在需要保留历史记录(例如用户账户,如@Jon Dewees所提到的)或者存在用户要求撤销删除操作的情况下,这是相当标准的做法。
如果你担心从查询中过滤掉已删除记录的逻辑会变得混乱并使查询变得复杂,那么你可以建立视图来为你进行过滤,并对其进行查询。这将防止这些记录泄露在报告解决方案等中。
我想对提到的唯一约束问题进行进一步解释。
假设我有一个表,包含两列:id
和my_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
需要更新为 (软删除行上最大的重复次数) + 1。
后者的逻辑必须通过触发器或在我的应用程序代码中处理程序来实现,并且没有可以设置的检查。
对于每个唯一的列都要重复这个过程!
我认为这种解决方案真的很杂乱,而且更倾向于使用一个单独的 归档 表来存储已删除的行。
他们不允许数据库按照应有的方式执行,导致级联功能等诸如此类的东西无用。
对于简单操作例如插入,在重新插入时,其后面的代码就会翻倍。
您不能仅仅简单地插入,而是必须检查是否存在,如果不存在则插入,否则更新删除标志,并将所有其他列更新为新值。这被视为对数据库事务日志的更新,而不是全新的插入,从而导致不准确的审计日志。
它们会导致性能问题,因为表格中存在冗余数据。这会对索引造成严重影响,特别是唯一性方面。
我不是逻辑删除的粉丝。
好吧!就像大家所说的,这取决于情况。
如果您在像UserName或EmailID这样的列上有一个索引 - 而且您永远不希望再次使用相同的UserName或EmailID,则可以选择软删除。
话虽如此,始终检查您的SELECT操作是否使用主键。如果您的SELECT语句使用主键,则添加带有WHERE子句的标志不会有太大的区别。让我们以一个示例为例(伪代码):
表Users(UserID [主键],EmailID,IsDeleted)
SELECT * FROM Users where UserID = 123456 and IsDeleted = 0
这个查询在性能上不会有任何影响,因为UserID列具有主键。最初,它将基于PK扫描表,然后执行下一个条件。
软删除无法完全起作用的情况:
在大多数网站上注册都使用EmailID作为唯一标识。我们非常清楚,一旦在像Facebook、G+这样的网站上使用了一个EmailID,其他人就不能再使用它。
当用户想从网站中删除他/她的个人资料时,就会出现这样的情况。现在,如果您进行逻辑删除,该用户将永远无法再次注册。此外,再次使用相同的EmailID注册并不意味着恢复整个历史记录。每个人都知道,删除意味着删除。在这种情况下,我们必须进行物理删除。但是,为了维护帐户的整个历史记录,我们应该始终将这些记录存档在归档表或已删除表中。
是的,在存在大量外部表的情况下,处理可能非常繁琐。
还要记住,软/逻辑删除会增加您的表大小和索引大小。
我已经在另一篇帖子中回答过了。 不过,我认为我的回答更适合这里的问题。
我的软删除实际解决方案是通过创建一个新表来进行归档,该表具有以下列:original_id
、table_name
、payload
(以及可选的主键id
)。original_id
是已删除记录的原始 ID,table_name
是已删除记录的表名(在您的情况下为"user"
),payload
是已删除记录所有列的 JSON 字符串化字符串。original_id
上建立索引,以便以后检索数据。WHERE
子句来检查删除