从表中删除记录时的前置或后置检查

Posted

技术标签:

【中文标题】从表中删除记录时的前置或后置检查【英文标题】:Pre or post check when deleting records from a table 【发布时间】:2012-06-08 14:06:11 【问题描述】:

对于经常删除记录的 Web 应用程序,如果我们考虑性能,什么是最好的?

检查该记录是否与其他表有关联,防止用户删除。

ex : 查询会是这样的

 if not exist(select * from table1 where tableX_id = @id) and 
       not exist(select * from table2 where tableX_id = @id)
       ...
    then 
       delete from tableX where id = @id 

执行delete 并让RDBMS 由于foriegn key 约束而引发错误

  try
       Service.DeleteRecord(id)
  catch
       Handle the error here
  

在这种情况下,查询会很简单

 delete from TableX where id = @id

【问题讨论】:

为什么不能对相关表使用级联删除? @Arion 我不想删除其他表中引用的记录 你为什么不想要那个?我的意思是您在删除时不必检查任何内容。您不必捕获任何错误。你可以让 sql-server 做“工作” @anouar204: CASCADE 被分配给单个 FK 引用,默认情况下它不会删除 所有内容,只会删除 FK 所源自的表。 我想说所有这些逻辑都应该在您调用以执行删除的任何存储过程中。让它只返回删除的行数并在代码中检查。如果您只是编写直接删除而不使用存储过程,则将代码转换为存储过程。 【参考方案1】:

如果目标是仅在实际运行删除会产生错误的情况下防止行被删除,因为它被其他表引用,那么我建议您在让 SQL Server 为您检查之前检查违规情况。 I've done some testing on this 并让 SQL 捕获错误或仅使用 TRY/CATCH 可能会更昂贵,如果您预计即使是中等数量的失败也是如此。有了适当的索引,执行检查的额外成本可以忽略不计;但是,不进行检查的成本肯定是可以忽略不计的。

【讨论】:

检查然后删除需要一个合适的事务(以及合适的隔离和锁定)来防止竞争 - 否则,你必须处理来自删除的错误的可能性。 在您的回答中“使用适当的索引”会产生重大影响,并且在其他情况下很可能会适得其反,或者由于其他业务原因根本无法做到。 @Damien_The_Unbeliever 是的,我不是说它是替代品,您可能仍需要尝试/捕获或其他错误处理,但如果在检查时行是否验证失败进入删除阶段是没有意义的,以防万一其他事务使删除成功成为可能。仍然使用 try/catch(或仅在验证检查成功时执行删除)仍将捕获在检查和删除之间删除无效的边缘情况。 您是否认为如果我们检查许多表,这些检查的成本仍然可以忽略不计? @anouar204 不确定我们是否可以就“可忽略”的含义达成一致,或者您编写的检查将如何优化,但如果 SQL Server 在尝试删除时必须进行这些检查,那该怎么办你在省钱吗?检查的好处是您可以自定义它们,以便首先检查最便宜的表(您无法控制违规),添加索引以支持您的检查(违规可能不会使用)等等。 【参考方案2】:

我会使用数据库触发器(或 ON CASCADE DELETE)来处理任何关系——可用的工具取决于您的 RDBMS。

【讨论】:

我不想删除其他表中引用的记录 既然您特意询问了检查与其他表的关系,您打算如何处理孤立的相关记录? 我认为这就是重点 - 如果他删除 X 中的一行,而 Y 中没有行指向它,它不会留下任何孤儿。 我要求检查以删除或不删除记录不进行清理 好的,既然您已经编辑了原始帖子,我更了解您的情况。由于这是删除记录与否的直接问题,因此我将执行存储过程中的逻辑并向应用程序返回布尔值、错误消息或其他指示符。【参考方案3】:

显然,执行删除并让 RDBMS 处理业务。通过自己实施检查,您会招致 RDBMS 无论如何都会执行的额外操作。

【讨论】:

以上是关于从表中删除记录时的前置或后置检查的主要内容,如果未能解决你的问题,请参考以下文章

从表中的多个重复项中删除特定记录

使用 SQLAlchemy 从表中删除记录

从表中删除孤立记录[关闭]

Mysql进阶4

从表中删除旧记录并在日期之前将这些记录备份到新备份表中

SQL查询:从表中删除除最新N之外的所有记录?