Ruby on rails 寻求优化ActiveRecord::destroy\u all的建议

Ruby on rails 寻求优化ActiveRecord::destroy\u all的建议,ruby-on-rails,activerecord,ruby-on-rails-5,rails-activerecord,Ruby On Rails,Activerecord,Ruby On Rails 5,Rails Activerecord,轨道5+ 我知道destroy\u all实例化每个模型并在其上运行destroy,并且delete\u all更快,但删除并不尊重: 销毁前,销毁前后和销毁后回调 依赖关系的设置 假设这个列表是全面的,我们是否应该通过检查模型的这些属性来节省时间,并且如果没有回调,就根据需要处理关系 编辑:我正在寻找一种方法来修改默认的destroy\u all行为,以便它更智能,不会盲目地实例化所有对象并链接对依赖关系的调用。如果我们有A与依赖B的关系(1:1),并且A很大(1 mil),那么需要实例化

轨道5+

我知道
destroy\u all
实例化每个模型并在其上运行
destroy
,并且
delete\u all
更快,但删除并不尊重:

  • 销毁前
    销毁前后
    销毁后
    回调
  • 依赖关系的设置
假设这个列表是全面的,我们是否应该通过检查模型的这些属性来节省时间,并且如果没有回调,就根据需要处理关系

编辑:我正在寻找一种方法来修改默认的
destroy\u all
行为,以便它更智能,不会盲目地实例化所有对象并链接对依赖关系的调用。如果我们有A与依赖B的关系(1:1),并且A很大(1 mil),那么需要实例化和销毁很多对象。是的,特定于应用程序/领域的知识意味着您可以调用
delete\u all
,但是如果有人更改模型并添加关系,那么
delete\u all
就变得非常危险了。如果我们优化
destroy\u all
来做一些思考,我们可以将一个简单的
dependent:delete
关系从关系a上的单个
destroy\u all
减少为两个
delete\u all
调用(a和B),其中原始的
destroy\u all
将是200万个对象实例化和DB命中

# Pseudocode
# Let the model in question be `User`

ids = self.pluck(:id)
if model.has_destroy_callbacks  # I imagine there's some fancy introspection stuff I can use 
  original_destroy_all
  return
else
  # Check Restrict type
  model.restrict_relationships.each do |rel|
    other_models = some_cute_query
    raise_exception_or_add_error if other_models.any?
  end

  # Add some check here to make sure we didn't miss any unknown dependency type

  # Normal relationships
  model.non_restrict_relationships.each do |rel|
    dep_type = rel.dependent_type
    if dep_type == :destroy
      rel.where(model_id: ids).destroy_all
    elsif dep_type == :delete
      rel.where(model_id: ids).delete_all
    elsif dep_type == :nullify
      rel.where(model_id: ids).update_all(model_name_id: nil)
    end
  end
end
self.delete_all # i.e. the collection that was gonna get destroyed
我要找的是,如果我遗漏了一些明显的东西,为什么这样做不起作用,那么我要做的就是检查我的心智是否健全。我也在寻找关于如何将其放入ActiveRecord的建议。另外,您是否可以针对特定模型上的集合/关系专门覆盖
destroy_all

回调链可以通过 对象活动模型回调支持
:在
之前,
:在
之后和
:作为种类属性的值围绕
。kind属性定义 回调运行在链的哪一部分

要查找“保存前”回调链中的所有回调,请执行以下操作:

Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
因此,在本例中,它的
\u destroy\u回调
,但如果您的目标是进行健全性检查,我会让该方法引发异常并退出,而不是调用
destroy\u all

raise SomeKindOfError if model._destroy_callbacks.any? 
这在调试和使用方面比仅仅隐藏问题要有用得多

获取模型的所有关联可以通过它来完成,从而为您提供AssociationReflection对象。从那里你可以得到协会的选项

但是
这充满了“聪明”代码的味道。当您发现使用销毁回调是一个性能问题时,会出现更大的问题,而只是在
delete\u all
destroy\u all
之间进行选择,而自动选择并不能真正解决问题

也许我的问题不清楚。我试图用它来代替destroy_all,这样它是递归的。现在,如果在一个包含许多记录的集合上调用destroy_all,则每个对象都会被实例化,并且必须销毁关联的对象。假设集合A和集合B有一个dependent::destroy操作,A和集合B有100万条记录,这就是大量的数据库命中,对吗?如果我们检测到可以全部删除两次,那就是两个DB调用vs 2mil obj实例化和查询要删除。