2010-02-04 20 views
13

रेल में एचएबीटीएम संबंध के साथ मेरे पास दो टेबल हैं। निम्नलिखित की तरह कुछ:रेल में बड़े पैमाने पर एचएबीटीएम संगठन बनाने का सबसे तेज़ तरीका क्या है?

 
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 

और दोनों वास्तव में धीमी गति से चलाने के प्रत्येक bar के लिए निम्नलिखित की तरह एक प्रवेश के साथ,: bars_foos एसक्यूएल से फ़ील्ड दिखाएं

bars_foos कॉलम (1.1ms) (0.6ms) bars_foos जांच सम्मिलित करें (bar_id, foo_id) मैं को देखा मान (100, 117200)

ar-एक्सटेंशन, लेकिन import फ़ंक्शन किसी मॉडल (मॉडल.इम्पपोर्ट) के बिना काम नहीं कर रहा है जो एक जॉइन टेबल के लिए इसका उपयोग रोकता है।

क्या मुझे एसक्यूएल लिखने की ज़रूरत है, या रेल के पास एक सुंदर तरीका है?

+0

वास्तव में? कोई नहीं? आप लोग सभी ले-अप और "सर्वोत्तम अभ्यास" प्रश्नों पर कूदते हैं :) – klochner

उत्तर

6

मुझे लगता है कि आपका सर्वश्रेष्ठ शर्त प्रदर्शन-वार एसक्यूएल का उपयोग करने जा रहा है, और प्रति पंक्ति एकाधिक पंक्तियों में थोक डालें। आप एक ही क्वेरी में पंक्तियों के हजारों सम्मिलित करने के लिए सक्षम होना चाहिए

INSERT INTO foos_bars (foo_id,bar_id) VALUES (1,1),(1,2),(1,3).... 

: यदि आप एक सम्मिलित कथन ऐसा ही कुछ होता है का निर्माण कर सकते हैं। मैं अपने mass_habtm विधि की कोशिश नहीं की है, लेकिन यह है कि आप की तरह कुछ कर सकते लगता है: यदि आप "some_attribute" द्वारा बार खोज रहे हैं

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}") 

इसके अलावा, सुनिश्चित करें कि आप उस क्षेत्र में अपने डेटाबेस सूचीबद्ध करा सकते हैं बनाते हैं।

+0

मेरा mass_habtm सिर्फ प्रश्नों को एक ही खोज/सम्मिलित क्वेरी में जोड़ता है, जो शायद आपके पास जो कुछ भी है उससे अधिक * प्राप्त नहीं करता है। मुझे अपना खुद का चयन करने से नफरत है, इसलिए कम से कम मुझे एक व्यवहार्य विकल्प देने के लिए धन्यवाद। – klochner

1

यह 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 

मुझे ऐसा लगता है कि यह एक सरल पर्याप्त आपरेशन है कि यह रेल में कुशलता से समर्थन किया जाना चाहिए है, मैं करने के लिए प्यार होता है सुनें कि किसी के पास क्लीनर तरीका है या नहीं।

मैं 2.2.2, चला रहा हूं शायद यह 3.x में अधिक कुशलतापूर्वक लागू किया गया है? और इसे 3.0.2 पर मिला।

-3

ईमानदारी से, has_and_belongs_to_many चीजों को करने का एक बहुत ही प्राचीन तरीका है। आपको शायद has_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 

इसके अलावा, आप उत्पादन में एक ही चलाने की कोशिश करें और प्रदर्शन आप किस तरह का मिलता है, के रूप में कैशिंग का एक बहुत उत्पादन जरूरी है कि विकास में नहीं होती में पर चला जाता है देखना चाहिए।

+1

झटका नहीं होना चाहिए, लेकिन आप किसी भी तरह से मुख्य प्रश्न - संबंध बनाने की गति को संबोधित करते हैं, यह अनुमान लगाने के अलावा कि उत्पादन बेहतर हो सकता है। जबकि कैशिंग मदद कर सकता है, यह लगभग निश्चित रूप से एसक्यूएल तैयार किए जाने के तरीके को नहीं बदलेगा। मैं यह भी तर्क दूंगा कि habtm इस सामान को अनुकूलित करने के लिए एक बेहतर उम्मीदवार है, क्योंकि has_many-> के माध्यम से एक मॉडल वर्ग की आवश्यकता होती है, जिसका अर्थ है कि मॉडल में कॉलबैक हो सकता है। – klochner

+1

और मुझे पूरा यकीन है कि आपका कार्यान्वयन * धीमा * है जिसे मैंने प्रस्तुत किया था * जितना तेज़ नहीं था *। – klochner

+0

हां, लेकिन जुड़ने पर एक मॉडल रखने से आप अन्य चीजों को खोजकर्ताओं और अन्य विकल्पों के साथ करने की अनुमति देते हैं जिनके लिए आपको पहुंच नहीं हो सकती है। कम से कम इस तरह, यदि आप आगे और आगे जाना चाहते हैं, तो दोनों मॉडलों में इसे दोहराने के बजाय आपके कोड को रखने के लिए एक और मॉडल है। –

5

आप अभी भी activerecord-import पर एक नज़र डाल सकते हैं। यह सही है कि यह मॉडल के बिना काम नहीं करता है, लेकिन आप केवल आयात के लिए मॉडल बना सकते हैं।

class FooBar < ActiveRecord::Base; end 

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

आप यह सुनिश्चित करने के लिए यहाँ के रूप में 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 
संबंधित मुद्दे