2013-09-05 64 views
3

我有類似以下內容:Rails的創建和保存散裝

module Bar < ActiveRecord::Base 
    belongs_to :foo 
    ... 

module Foo < ActiveRecord::Base 
    has_many :bars, dependent: :destroy 

    def build_bars 
    1000.times do |i| 
     bars.build(num: i) 
    end 
    end 

    def create_default_bars! 
    build_bars 
    save 
    end 

注意Foo#build_bars便宜。即使循環1000次,也只需很少的時間。但是,一旦你點擊了save,突然ActiveRecord決定執行1000次插入,這非常慢。

我如何寫一個自定義save_the_bars方法使得其執行對所有bars我已經建立了一個單一的BULK INSERT查詢(我提醒你,1000 build s爲顯然是很便宜),但其功能是作爲這個例子中的save的替代品是什麼?


我期待沿着這個博客帖子的推薦#3線回答:

https://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/

但因爲我的示例使用build和依賴於一些稍微平凡的軌道魔法,它如何翻譯它並不是很明顯。基準獎勵積分!

回答

2

我會嘗試activerecord-import寶石。

def save_the_bars(bars) 
    Bars.import bars 
end 

這次調用進口爲所欲爲是最有效的底層數據庫適配器。很漂亮,呃?

獎勵積分:Benchmarks


問題,提問者在這裏,對我做了什麼遵循上述建議劫持這個答案與細節:

def build_bars 
    built_bars = [] 
    1000.times do |i| 
    built_bars << bars.build(num: i) 
    end 
    built_bars 
end 

def create_default_bars 
    save 
    Bar.insert built_bars, validate: false 
    reload 
end 

這給了一個很好的加速比相對較少的努力。我仍然懷疑可以有更多的加速(通過利用insert的細微差別),但我現在對此感到滿意。在我的使用案例中,關閉驗證是安全的,因爲生成所有Bar的方法可以保證生成有效的驗證。

+0

很酷,我會試試看。 –