在Rails中创建大规模HABTM关联的最快方法是什么?

klo*_*ner 14 activerecord ruby-on-rails 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_some_attribute(:a)

最快的方法是什么?我试过了:

@foo.bars = @bars
@foo.bars << @bars
Run Code Online (Sandbox Code Playgroud)

两者都运行得很慢,每个条目都有以下条目bar:

bars_foos列(1.1ms)从bars_foos SQL 显示字段(0.6ms)INSERT INTO bars_foos(bar_id, foo_id)VALUES(100,117200)

我查看了ar-extensions,但是import如果没有模型(Model.import),该函数似乎无法工作,因为它不能用于连接表.

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

Pet*_*own 7

我认为在性能方面最好的选择是使用SQL,并为每个查询批量插入多行.如果您可以构建一个类似于以下内容的INSERT语句:

INSERT INTO foos_bars (foo_id,bar_id) VALUES (1,1),(1,2),(1,3)....
Run Code Online (Sandbox Code Playgroud)

您应该能够在单个查询中插入数千行.我没有尝试你的mass_habtm方法,但似乎你可以这样:

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}")
Run Code Online (Sandbox Code Playgroud)

此外,如果您通过"some_attribute"搜索Bar,请确保在数据库中将该字段编入索引.


小智 7

您仍然可以查看activerecord-import.没有模型它是不行的,但你可以创建一个仅用于导入的模型.

class FooBar < ActiveRecord::Base; end

FooBar.import [:foo_id, :bar_id], [[1,2], [1,3]]
Run Code Online (Sandbox Code Playgroud)

您可以将其包装在事务中以确保HABTM完全填充,如下所示:

ActiveRecord::Base.transaction do
  imported_foo = Foo.import( foo_names, foo_values )
  imported_bar = Bar.import( bar_names, bar_values )
  FooBar.import( [:foo_id, :bar_id], imported_foo.ids.zip(imported_bar.ids)
end
Run Code Online (Sandbox Code Playgroud)