我有要检索的ID序列.这很简单:
session.query(Record).filter(Record.id.in_(seq)).all()
有没有更好的方法呢?
你的代码绝对好.
IN
就像一堆X=Y
加入,OR
在当代数据库中相当快.
但是,如果您的ID列表很长,则可以通过传递返回ID列表的子查询来提高查询效率.
代码完全没问题.然而,有人要求我在两个做大IN的方法和使用个人ID的get()之间进行一些对冲系统.
如果有人真的试图避免使用SELECT,那么最好的方法就是提前在内存中设置所需的对象.比如,你正在研究一个大的元素表.将工作分解为块,例如,按主键或日期范围排序整套工作,然后将该块的所有内容本地加载到缓存中:
all_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_]
这是现实世界的用例.
但是为了说明一些SQLAlchemy API,我们可以创建一个函数来为我们没有的记录创建IN,为我们做的那些创建本地get.这是:
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
这是一个演示:
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