Ruby on rails 在Rails中创建大量HABTM关联的最快方法是什么?

Ruby on rails 在Rails中创建大量HABTM关联的最快方法是什么?,ruby-on-rails,activerecord,has-and-belongs-to-many,Ruby On Rails,Activerecord,Has And Belongs To Many,我有两个表,在Rails中有一个HABTM关系。如下所示: class Foo < ActiveRecord::Base has_and_belongs_to_many :bars end class Bar < ActiveRecord::Base has_and_belongs_to_many :foos end 现在,我有了一个新的Foo对象,并希望为其批量分配数千个条,我已经预先加载了: @foo = Foo.create @bars = Bar.find_all_by

我有两个表,在Rails中有一个HABTM关系。如下所示:

class Foo < ActiveRecord::Base
  has_and_belongs_to_many :bars
end

class Bar < ActiveRecord::Base
  has_and_belongs_to_many :foos
end
现在,我有了一个新的
Foo
对象,并希望为其批量分配数千个条,我已经预先加载了:

@foo = Foo.create
@bars = Bar.find_all_by_some_attribute(:a)
最快的方法是什么?我试过:

@foo.bars = @bars
@foo.bars << @bars
两个都运行得非常慢,每个
条都有如下条目:

条形图和柱形图(1.1ms)显示 来自
bar\u foos
SQL的字段(0.6ms) 插入
bar\u foos
bar\u id
),
foo_id
)值(100117200)

我查看了ar扩展,但是如果没有一个模型(model.import),import函数似乎无法工作,因为模型(model.import)阻止了它对联接表的使用


我是否需要编写SQL,或者Rails是否有更漂亮的方式?

这比等效的本机Rails代码快7倍:

class << Foo
  def mass_habtm(attr_array)
    attr_str = attr_array.map{|a| %Q{'#{a}'} }.uniq.join(",")
    self.connection.execute(%Q{insert into foos_bars (foo_id,bar_id) 
                     select distinct foos.id,bars.id from foos,bars 
                     where foos.id = #{self.id} 
                     and bars.some_attribute in (#{attr_str})})
  end
end
在我看来,这是一个足够简单的操作,它应该在Rails中得到有效的支持,我很想听听是否有人有更干净的方法


我正在运行2.2.2,也许它在3.x中实现得更有效?而且在3.0.2上也发现了同样的情况。

老实说,
拥有而且属于很多人
是一种非常过时的做事方式。您可能应该研究一下
has\u many:through
,这是处理联接表的新方法,已经有相当一段时间了

class Foo < ActiveRecord::Base
  has_many :foobars
  has_many :bars, :through => :foobars

  def add_many_bars(bars)
    bars.each do |bar|
      self.bars << bar
    end
  end
end

class Bar < ActiveRecord::Base
  has_many :foobars
  has_many :foos, :through => :foobars
end

class FooBar < ActiveRecord::Base
  belongs_to :foo
  belongs_to :bar
end
class Foo:foobars
def添加多条(条)
酒吧。每个都有酒吧|
self.bar:foobars
结束
类FooBar

此外,您应该尝试在生产环境中运行相同的缓存,看看您获得了什么样的性能,因为在生产环境中进行的大量缓存在开发过程中并不一定会发生。

我认为最好的性能选择是使用SQL,并在每个查询中批量插入多行。如果可以生成执行以下操作的INSERT语句:

INSERT INTO foos_bars (foo_id,bar_id) VALUES (1,1),(1,2),(1,3)....
bars = Bar.find_all_by_some_attribute(:a)
foo = Foo.create
values = bars.map {|bar| "(#{foo.id},#{bar.id})"}.join(",")
connection.execute("INSERT INTO foos_bars (foo_id, bar_id) VALUES #{values}")
您应该能够在一个查询中插入数千行。我没有尝试你的mass_habtm方法,但你似乎可以这样做:

INSERT INTO foos_bars (foo_id,bar_id) VALUES (1,1),(1,2),(1,3)....
bars = Bar.find_all_by_some_attribute(:a)
foo = Foo.create
values = bars.map {|bar| "(#{foo.id},#{bar.id})"}.join(",")
connection.execute("INSERT INTO foos_bars (foo_id, bar_id) VALUES #{values}")

另外,如果您正在按“some_属性”搜索工具栏,请确保在数据库中对该字段进行了索引。

您仍然可以查看。没有模型它就不能工作,这是正确的,但是您可以创建一个只用于导入的模型

class FooBar < ActiveRecord::Base; end

FooBar.import [:foo_id, :bar_id], [[1,2], [1,3]]

真正地没有人?你们这些家伙在上篮和“最佳实践”问题上跳来跳去:)不想成为一个混蛋,但你们根本没有解决主要问题——建立关系的速度,只是猜测生产可能会更好。虽然缓存可能会有所帮助,但它几乎肯定不会改变SQL的格式。我还认为habtm是优化这些东西的更好的候选者,因为has_many->through需要一个模型类,这意味着连接模型中可能会有回调。我非常确定您的实现比我之前介绍的慢,因为速度不够快。是的,但是,在连接上有一个模型可以让您使用查找器和其他您可能无法访问的选项执行其他操作。至少通过这种方式,如果你想来回的话,你可以在另一个模型中放入你的代码,而不是在两个模型中重复它。my mass_habtm只是将查询合并到一个搜索/插入查询中,这可能比你在这里得到的不多。我讨厌自己选择,所以至少感谢你给了我一个可行的选择。