2009-01-14 13 views
25

मेरे पास आईडी का अनुक्रम है जिसे मैं पुनर्प्राप्त करना चाहता हूं। यह आसान है:sqlalchemy, ऑब्जेक्ट्स की सूची में आईडी की एक सूची को बदलना

session.query(Record).filter(Record.id.in_(seq)).all() 

क्या ऐसा करने का कोई बेहतर तरीका है?

+1

क्या आप इसके बारे में पसंद नहीं है:

from sqlalchemy import inspect def get_all(session, cls, seq): mapper = inspect(cls) lookup = set() for ident in seq: key = mapper.identity_key_from_primary_key((ident,)) if key in session.identity_map: yield session.identity_map[key] else: lookup.add(ident) if lookup: for obj in session.query(cls).filter(cls.id.in_(lookup)): yield obj 

यहाँ एक प्रदर्शन है: यहाँ है? क्या यह काम नहीं करता है? ऐसा लगता है कि यह चाहिए। –

+0

यह काम करता है, मैं बस सोच रहा था कि ऐसा करने के लिए कुछ अच्छा तरीका था या नहीं। – Cheery

+1

"nicer" से आपका क्या मतलब है? आपको इसके बारे में क्या पसंद नहीं है? –

उत्तर

13

आपका कोड पूर्णता ठीक है।

INX=Y के समूह की तरह OR के साथ जुड़ गया है और समकालीन डेटाबेस में बहुत तेज है।

हालांकि, यदि आपकी आईडी की सूची लंबी है, तो आप आईडी की सूची लौटने वाली उप-क्वेरी पास करके क्वेरी को थोड़ा अधिक कुशल बना सकते हैं।

1

मैं इसे उत्पन्न एसक्यूएल पर एक नज़र डालने की सलाह दूंगा। आप इसे देखने के लिए केवल str (क्वेरी) प्रिंट कर सकते हैं।

मुझे मानक एसक्यूएल के साथ ऐसा करने का एक आदर्श तरीका पता नहीं है।

2

आप समग्र प्राथमिक कुंजी का उपयोग करते हैं, तो आप में

from sqlalchemy import tuple_ 
session.query(Record).filter(tuple_(Record.id1, Record.id2).in_(seq)).all() 

नोट के रूप में tuple_ उपयोग कर सकते हैं, कि यह (doc देखें) SQLite पर उपलब्ध नहीं है।

+0

धन्यवाद कि मैं वही था जो मैं ढूंढ रहा था! – Dionys

1

एक और तरीका है; यदि यह अपेक्षा करना उचित है कि प्रश्न में वस्तुएं पहले ही सत्र में लोड हो चुकी हैं; आप एक ही लेन-देन में पहले उन्हें एक्सेस किया है, आप के बजाय कर सकते हैं:

map(session.query(Record).get, seq) 

मामले में जहां उन वस्तुओं पहले से मौजूद हैं में, यह बहुत तेजी से हो जाएगा, के बाद से वहाँ किसी भी प्रश्न उन को पुनः प्राप्त करने नहीं होगा वस्तुओं; दूसरी तरफ, यदि उन वस्तुओं की एक छोटी संख्या से अधिक लोड नहीं हैं, तो यह बहुत अधिक धीमा होगा, क्योंकि यह सभी वस्तुओं के लिए एक प्रश्न के बजाय प्रति गायब उदाहरण के लिए एक क्वेरी का कारण बन जाएगा।

यह तब उपयोगी हो सकता है जब आप ऊपर दिए गए चरण तक पहुंचने से पहले joinedload() क्वेरी कर रहे हैं, ताकि आप सुनिश्चित हो सकें कि वे पहले ही लोड हो चुके हैं। आम तौर पर, आपको डिफ़ॉल्ट रूप से प्रश्न में समाधान का उपयोग करना चाहिए, और केवल इस समाधान का पता लगाना चाहिए जब आपने देखा है कि आप एक ही वस्तु के लिए पूछताछ कर रहे हैं।

5

जैसा कोड पूरी तरह से ठीक है। हालांकि, कोई मुझे व्यक्तिगत आईडी के लिए get() का उपयोग करके एक बड़ा बनाम बनाम के दो दृष्टिकोणों के बीच हेजिंग के कुछ सिस्टम के लिए पूछ रहा है।

यदि कोई वास्तव में चयन से बचने की कोशिश कर रहा है, तो ऐसा करने का सबसे अच्छा तरीका समय से पहले स्मृति में आवश्यक वस्तुओं को सेट करना है। जैसे, आप तत्वों की एक बड़ी मेज पर काम कर रहे हैं। जैसे मात्रा, में काम को तोड़ने के प्राथमिक कुंजी द्वारा काम का पूरा सेट के आदेश, या तिथि सीमा से जो कुछ भी है, तो स्थानीय स्तर पर एक कैश में है कि हिस्सा के लिए सब कुछ लोड:

all_ids = [<huge list of ids>] 

all_ids.sort() 
while all_ids: 
    chunk = all_ids[0:1000] 

    # bonus exercise! Throw each chunk into a multiprocessing.pool()! 
    all_ids = all_ids[1000:] 

    my_cache = dict(
      Session.query(Record.id, Record).filter(
       Record.id.between(chunk[0], chunk[-1])) 
    ) 

    for id_ in chunk: 
     my_obj = my_cache[id_] 
     <work on my_obj> 

असली दुनिया फायदा नहीं है यही कारण है कि मामला।

लेकिन कुछ एसक्यूएलकेमी एपीआई को भी चित्रित करने के लिए, हम एक ऐसा फ़ंक्शन बना सकते हैं जो हमारे पास रिकॉर्ड के लिए आईएन करता है और स्थानीय लोग हमारे लिए करते हैं।

from sqlalchemy import Column, Integer, create_engine, String 
from sqlalchemy.orm import Session 
from sqlalchemy.ext.declarative import declarative_base 
import random 

Base = declarative_base() 


class A(Base): 
    __tablename__ = 'a' 
    id = Column(Integer, primary_key=True) 
    data = Column(String) 

e = create_engine("sqlite://", echo=True) 
Base.metadata.create_all(e) 

ids = range(1, 50) 

s = Session(e) 
s.add_all([A(id=i, data='a%d' % i) for i in ids]) 
s.commit() 
s.close() 

already_loaded = s.query(A).filter(A.id.in_(random.sample(ids, 10))).all() 

assert len(s.identity_map) == 10 

to_load = set(random.sample(ids, 25)) 
all_ = list(get_all(s, A, to_load)) 

assert set(x.id for x in all_) == to_load 
संबंधित मुद्दे