delete_all vs destroy_all?
Posted
技术标签:
【中文标题】delete_all vs destroy_all?【英文标题】:delete_all vs destroy_all? 【发布时间】:2011-10-05 14:34:24 【问题描述】:我正在寻找从表中删除记录的最佳方法。例如,我有一个用户,其用户 ID 跨越许多表。我想删除该用户以及所有表中具有其 ID 的每条记录。
u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
u.sources.destroy_all
u.user_stats.destroy_all
u.delete
这有效并从所有表中删除了用户的所有引用,但我听说destroy_all
的过程非常繁重,所以我尝试了delete_all
。它只会从他自己的用户表中删除用户,并且将所有其他表中的id
设为空,但保留其中的记录完好无损。有人可以分享执行此类任务的正确流程吗?
我看到destroy_all
对所有关联对象调用了destroy
函数,但我只想确认正确的方法。
【问题讨论】:
【参考方案1】:你是对的。如果要删除用户和所有关联对象 -> destroy_all
但是,如果您只想删除用户而不抑制所有关联对象 -> delete_all
根据这个帖子:Rails :dependent => :destroy VS :dependent => :delete_all
destroy
/ destroy_all
: 关联对象通过调用其destroy方法与该对象一起销毁
delete
/ delete_all
: 所有关联的对象都会立即销毁而不调用它们的 :destroy 方法
【讨论】:
还需要注意的是1)使用delete_all
时不会调用回调,2)destroy_all
实例化所有记录,一次销毁一个,所以对于非常大的数据集,这可能会非常缓慢。
假设我在模型中运行 before_destroy 方法 - 如果我使用 delete_all 那么这个方法不会运行?其次,如果我在模型中使用 before_delete 方法,当我在 rails 控制台中运行 delete 或 delete_all 时,它会运行吗?【参考方案2】:
delete_all 是一条 SQL DELETE 语句,仅此而已。 destroy_all 对 :conditions (如果有的话)的所有匹配结果调用 destroy() ,这可能至少是 NUM_OF_RESULTS SQL 语句。
如果您必须在大型数据集上执行诸如 destroy_all() 之类的激烈操作,我可能不会从应用程序中执行此操作并小心手动处理。如果数据集足够小,您不会受到太大伤害。
【讨论】:
【参考方案3】:为避免destroy_all
实例化所有记录并一次销毁它们,您可以直接从模型类中使用它。
所以不是:
u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
你可以这样做:
u = User.find_by_name('JohnBoy')
UsageIndex.destroy_all "user_id = #u.id"
结果是一次查询销毁所有关联记录
【讨论】:
它会在关联记录上调用销毁回调,还是UsageIndex.destroy_all
等同于UsageIntex.delete_all
?
UsageIndex.destroy_all
自 rails 3 起不再可用【参考方案4】:
我制作了一个small gem,可以在某些情况下减少手动删除关联记录的需要。
此 gem 为 ActiveRecord 关联添加了一个新选项:
依赖: :delete_recursively
当您销毁记录时,使用此选项关联的所有记录都将被递归删除(即跨模型),而不实例化任何记录。
请注意,就像dependent: :delete 或dependent: :delete_all 一样,这个新选项不会触发依赖记录的around/before/after_destroy 回调。
然而,在一个模型链中的任何地方都可以有dependent: :destroy 关联,否则这些关联是与dependent: :delete_recursively 关联的。 :destroy 选项将在任何地方正常工作,实例化和销毁所有相关记录,从而触发它们的回调。
【讨论】:
这太棒了!我想知道为什么没有更多的人在 github 上观看/加星标/分叉它。它仍然运作良好吗? @Magne 谢谢!它应该工作。测试在 Ruby 2.4.1 和 Rails 5.1.1 上运行。到目前为止,我只是私下使用它,而不是在主要的生产应用程序中使用它,因此主要版本为“0”,但我从未注意到任何问题。它也相当简单,所以应该没问题。 酷。 :) 我在 Ruby 2.3.1 和 'rails'、'~>4.1.14' 上运行一个项目,但遗憾的是,由于其他 gem,我不得不依赖 activerecord (~> 4.1.0)。我看到 delete_recursively 被解析为 0.9.0。是否有可以与 activerecord 4.1 一起使用的旧版本?我在 github 上的发布选项卡中找不到任何内容。 @Magne 我发现它实际上是works for activerecord as low as 4.1.14 并且已经发布了gem 1.0.0 版,它具有轻松的依赖关系。不过请记住,Rails 的 4.1 分支不再接收安全更新。以上是关于delete_all vs destroy_all?的主要内容,如果未能解决你的问题,请参考以下文章