2010-02-23 12 views
8

मेरे पास sqlalchemy ORM मैपिंग का उपयोग करते हुए स्क्लाइट डेटाबेस से उत्पन्न वस्तुओं का एक जटिल नेटवर्क है। मैं काफी कुछ गहरा नीडिंत है:केवल पढ़ने योग्य ऑब्जेक्ट मॉडल के लिए SQLAlchemy ऑप्टिमाइज़ेशन

for parent in owner.collection: 
    for child in parent.collection: 
     for foo in child.collection: 
      do lots of calcs with foo.property 

मेरे रूपरेखा मुझे दिख रहा है कि SQLAlchemy उपकरण उपयोग के इस मामले में बहुत समय ले रहा है।

बात यह है कि: मैंने कभी भी रनटाइम पर ऑब्जेक्ट मॉडल (मैप किए गए गुण) को कभी नहीं बदला है, इसलिए एक बार जब वे लोड हो जाते हैं तो मुझे उपकरण की आवश्यकता नहीं होती है, या वास्तव में किसी भी स्क्लेल्केमी ओवरहेड की आवश्यकता नहीं होती है। बहुत से शोध के बाद, मुझे लगता है कि मुझे अपने पहले से लोड 'वाद्य यंत्र' से ऑब्जेक्ट्स के 'शुद्ध पायथन' सेट को क्लोन करना पड़ सकता है, लेकिन यह दर्द होगा।

प्रदर्शन वास्तव में यहां महत्वपूर्ण है (यह एक सिम्युलेटर है), इसलिए शायद उन परतों को एसक्लाइट एपीआई का उपयोग करके सी एक्सटेंशन के रूप में लिखना सीधे सबसे अच्छा होगा। कोई विचार?

उत्तर

7

यदि आप एक ही उदाहरण के एक ही गुण को कई बार संदर्भित करते हैं, तो एक साधारण चाल इसे स्थानीय चर में संग्रहीत करना है।

आप एक तरह से सस्ते शुद्ध अजगर क्लोन बनाने के लिए, मूल वस्तु के साथ dict वस्तु का हिस्सा चाहते हैं:

class CheapClone(object): 
    def __init__(self, original): 
     self.__dict__ = original.__dict__ 

एक प्रति बनाई जा रही इस instrumented विशेषता का उपयोग के बारे में आधे की लागत की तरह और विशेषता लुकअप के रूप में कर रहे हैं सामान्य के रूप में तेज़।

मैपर एक उपकरण के बजाए एक निर्विवाद वर्ग के उदाहरण बनाने का एक तरीका भी हो सकता है। यदि मेरे पास कुछ समय है, तो मैं देख सकता हूं कि कितनी गहराई से यह माना जाता है कि जनसंख्या वाले उदाहरण साधन वर्ग के समान प्रकार के होते हैं।


एक त्वरित और गंदा तरीका मिला जो कम से कम कुछ हद तक 0.5.8 और 0.6 पर काम करता है। विरासत या अन्य सुविधाओं के साथ इसका परीक्षण नहीं किया जो बुरी तरह से बातचीत कर सकता है। साथ ही, यह कुछ गैर-सार्वजनिक एपीआई को छूता है, इसलिए संस्करणों को बदलते समय ब्रेकेज से सावधान रहें।

from sqlalchemy.orm.attributes import ClassManager, instrumentation_registry 

class ReadonlyClassManager(ClassManager): 
    """Enables configuring a mapper to return instances of uninstrumented 
    classes instead. To use add a readonly_type attribute referencing the 
    desired class to use instead of the instrumented one.""" 
    def __init__(self, class_): 
     ClassManager.__init__(self, class_) 
     self.readonly_version = getattr(class_, 'readonly_type', None) 
     if self.readonly_version: 
      # default instantiation logic doesn't know to install finders 
      # for our alternate class 
      instrumentation_registry._dict_finders[self.readonly_version] = self.dict_getter() 
      instrumentation_registry._state_finders[self.readonly_version] = self.state_getter() 

    def new_instance(self, state=None): 
     if self.readonly_version: 
      instance = self.readonly_version.__new__(self.readonly_version) 
      self.setup_instance(instance, state) 
      return instance 
     return ClassManager.new_instance(self, state) 

Base = declarative_base() 
Base.__sa_instrumentation_manager__ = ReadonlyClassManager 

प्रयोग उदाहरण:

class ReadonlyFoo(object): 
    pass 

class Foo(Base, ReadonlyFoo): 
    __tablename__ = 'foo' 
    id = Column(Integer, primary_key=True) 
    name = Column(String(32)) 

    readonly_type = ReadonlyFoo 

assert type(session.query(Foo).first()) is ReadonlyFoo 
+1

दुर्भाग्य से उपयोग पैटर्न कई छोटी वस्तुओं में कई गणना है, इसलिए स्थानीय कैशिंग बहुत उपयोगी नहीं है। क्लोनिंग विचार वास्तव में जाने के रास्ते की तरह लगता है, त्वरित टिप के लिए धन्यवाद। आपकी अंतिम टिप्पणी बिल्कुल वही है जो मैं चाहूंगा: मैपर से 'अनजान' वर्ग बनाने के लिए कहें, क्योंकि मुझे पता है कि यह केवल पढ़ने के लिए है। – CarlS

+0

धन्यवाद एक गुच्छा! मैं इसे आजमाने के लिए इंतजार नहीं कर सकता। – CarlS

+0

मैंने मैपर हैक पर कुछ शुरुआती काम किया है और समय अंतर अंतरदायक हैं। मैं के लिए xrange में (500000): एक साधारण पाश के लिए foo = readonlyobj.attr_bar सामान्य उपकरण के साथ: 2.663 सेकेंड केवल पढ़ने के लिए नक्शाकार हैक साथ : 0.078 सेकेंड एक बहुत ही महत्वपूर्ण परिणाम imo है यही कारण है, इसलिए धन्यवाद फिर से। मैं अभी भी वास्तव में यह समझने की कोशिश कर रहा हूं कि यह कैसे काम करता है और यह थोड़ा अधिक गहराई में स्क्लेल्चेमी सीखने का एक शानदार तरीका साबित कर रहा है। – CarlS

-1

पाइथन लूप के बजाय जॉइन के साथ एक ही क्वेरी का उपयोग करने का प्रयास करें।

+0

धन्यवाद, लेकिन ORM की बात की जा रही है कि उन कंटेनरों समझदारी से मुझे के लिए भरे जाएंगे नहीं है? मैं उस लाभ को खोने से नफरत करता हूं। मैंने कुछ सीमित परीक्षण भी किए हैं और यह वास्तव में एक बड़ी क्वेरी चलाने के लिए धीमा हो सकता है और परिणाम द्वारा ResultProxy पंक्ति को संसाधित कर सकता है, जिस बिंदु पर मैं अभी भी 'foo.property' पहुंच के लिए भुगतान कर रहा हूं। – CarlS

+0

ओआरएम सामान केवल ऑब्जेक्ट उन्मुख तरीके से rdbms के साथ काम करना आसान बनाता है। संबंधपरक डीबीएस से संबंधपरक नहीं है। – ebo

0

आप प्रश्न में रिश्तों पर आलसी लोडिंग को अक्षम करने में सक्षम होना चाहिए और sqlalchemy उन्हें सभी को एक ही प्रश्न में लाएगा।

+0

यह क्वेरी की गति इतनी अधिक नहीं है जितना कि हजारों 'वाद्य यंत्र' करने के सरल ओवरहेड ऑब्जेक्ट गुणों, यानी 'foo.property' तक पहुंच जाता है। – CarlS

+0

यह उपयोग पैटर्न, आलसी लोड होने पर, अक्सर प्रत्येक लूप के प्रत्येक पुनरावृत्ति के लिए एक अलग चयन कथन उत्पन्न करेगा। (आमतौर पर यदि आप टेस्ट रन के दौरान SQL आउटपुट चालू करते हैं तो दिखाई देता है।) यही कारण है कि मेरी पहली प्रतिक्रिया यह थी। –

+0

ठीक है, मैं इसे दोबारा जांचूंगा: आखिरी बार जब मैंने डीबगिंग किया था तो मुझे याद है कि एसक्यूएल अपफ्रंट का एक समूह देख रहा है लेकिन लूप्स के दौरान कोई नहीं।मुझे यह इंगित करना चाहिए कि मैं एक मोंटे-कार्लो सिम्युलेटर लिख रहा हूं, इसलिए इन लूपों को 100000 बार चलाया जा रहा है (मुझे यह जांचना होगा कि कंटेनरों को लाने के लिए एसक्यूएल केवल एक बार किया जा रहा है)। – CarlS

संबंधित मुद्दे