【问题标题】:Rails: Object destroy performanceRails:对象破坏性能
【发布时间】:2013-09-29 17:14:40
【问题描述】:

在我的 Rails 应用程序中。我有我的基本模型 - 用户。有很多与用户相关的对象。

Class User 
 has_many :contents, dependent: destroy
 has_many :messages, dependent: destroy
 has_many :ratings, dependent: destroy
 has_many :groups, dependent: destroy
 ...
end

当我想从我的系统中删除用户(销毁用户对象)时,大约需要一分钟来销毁所有关联的对象。处理此类情况的最佳方法是什么?

我想到的一种方法是:

在delayed_job中销毁:

但是直到用户对象在延迟作业中被销毁之前,该用户不应该对其他人可见。通过在用户模型中删除标志而不获取结果来处理这种情况。但我也使用 sphinx,并且需要确保该用户也不会出现在 sphinx 结果中。

有没有更好的方法来处理这种情况?

【问题讨论】:

  • 一种选择是先销毁用户,然后将相关对象的销毁委托给延迟作业。
  • 您是否考虑过使用delete 而不是destroyapi.rubyonrails.org/classes/ActiveRecord/Associations/…
  • @gabrielhilal 是的。但在删除的情况下,观察者回调不会发生,我也必须手动进行。就像破坏用户破坏组一样,组又必须更新计数并删除组中的活动。单独处理它们会使代码有点复杂。但就是这样吗?

标签: ruby-on-rails ruby-on-rails-3


【解决方案1】:

挑战在于,您可能已经知道,.destroy 方法将加载每个子对象,然后调用它们的.destroy 方法。

这里的价值是在进行最终销毁之前评估子级的任何回调。因此,如果孩子需要清理其他地方的任何东西,那么它会这样做。此外,如果依赖对象在销毁方法期间抛出错误,整个销毁操作将回滚,并且您最终不会有一些半死的对象一瘸一拐地四处走动。

.delete 将销毁对象而不将它们加载到内存中或执行它们的回调。但是(显然)它不会执行他们的回调。

如果你想加快速度,你可以像 Octopus-Paul 建议的那样简单地做dependent: :delete。这很好,但它不会破坏这些对象的依赖项,因此,例如,如果组有与之关联的消息,或者评级可能与它们关联的 cmets,则这些都不会被破坏。

为了确保所有下游依赖项都被销毁并尊重任何必要的回调,我认为您能做的最好的事情就是编写一个自定义的 before_destroy 方法,该方法会清除所有内容,但使用 .delete.delete_all 以加快速度。

这将产生遗留问题,即下游编写代码的人不一定能预料到您的方法,但您可以判断其风险。另一种方法(如您所说)是使用标志并异步完成工作。我想这在未来的风险较小,但今天实施起来可能会更昂贵。

【讨论】:

    【解决方案2】:

    :依赖

    控制关联对象在其所有者被销毁时发生的情况:

    :destroy causes the associated object to also be destroyed
    :delete causes the associated object to be deleted directly from the database (so callbacks will not execute)
    

    删除会更快,因为它会简单地为已删除用户的每个关联运行数据库查询。

    在此处查找更多选项:http://guides.rubyonrails.org/association_basics.html#options-for-has-one-dependent

    【讨论】:

    • 感谢@Octopus-Paul。但是我的关联对象又具有自己的关联。喜欢组有很多活动。所以破坏组必须破坏它的关联。
    • 在这种情况下你不能使用 :delete :D
    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 2010-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多