如何在 SQLAlchemy 中使用空集合进行分页查询?
Posted
技术标签:
【中文标题】如何在 SQLAlchemy 中使用空集合进行分页查询?【英文标题】:How to do a paged query with empty collections in SQLAlchemy? 【发布时间】:2012-11-28 05:00:37 【问题描述】:我正在尝试找到一种内存有效的方法来执行分页查询以测试空集合,但似乎无法弄清楚如何在大型数据库上有效地执行它。表格布局使用具有双向反向引用的关联对象。它与documentation 非常相似。
class Association(Base):
__tablename__ = 'Association'
assoc_id = Column(Integer, primary_key=True, nullable=False, unique=True)
member_id = Column(Integer, ForeignKey('Member.id'))
chunk_id = Column(Integer, ForeignKey('Chunk.id'))
extra = Column(Text)
chunk = relationship("Chunk", backref=backref("assoc", lazy="dynamic"))
class Member(Base):
__tablename__ = 'Member'
id = Column(Integer, primary_key=True, nullable=False, unique=True)
assocs = relationship("Association", backref="member", cascade="all, delete", lazy="dynamic")
class Chunk(Base):
__tablename__ = 'Chunk'
id = Column(Integer, primary_key=True, nullable=False, unique=True)
name = Column(Text, unique=True)
如果会员被删除,会级联删除会员的关联。但是,块对象将在数据库中成为孤立对象。要删除孤立的块,我可以使用这样的查询来测试空集合:
session.query(Chunk).filter(~Chunk.assoc.any())
然后删除块:
query.delete(synchronize_session=False)
但是,如果关联表和块表很大,则查询或子查询似乎会加载所有内容并且内存会猛增。
我看到了使用分页查询来限制标准查询的内存使用的概念here:
def page_query(q, count=1000):
offset = 0
while True:
r = False
for elem in q.limit(count).offset(offset):
r = True
yield elem
offset += count
if not r:
break
for chunk in page_query(Session.query(Chunk)):
print chunk.name
但是,这似乎不适用于空集合查询,因为内存使用率仍然很高。有没有办法对这样的空集合进行分页查询?
【问题讨论】:
【参考方案1】:我发现这里缺少一些东西。空块的查询似乎大部分都可以。我看到的内存使用高峰来自代码中几行之前的查询,当时实际成员本身已被删除。
member = session.query(Member).filter(Member.name == membername).one()
session.delete(member)
根据文档,会话(默认情况下)只能删除加载到会话/内存中的对象。当成员被删除时,它将加载它的所有关联,以便按照级联规则删除它们。需要发生的是,必须使用 passive deletes 绕过关联加载。
我补充说:
passive_deletes=True
到Member类的关联关系和:
ondelete='CASCADE'
到 Association 类的 member_id 外键。我正在使用 SQLite3,并通过 docs 的引擎连接事件添加了外键支持。
关于孤立块,而不是使用 query.delete 方法批量删除块。我使用了一个不包含偏移量的页面查询,并在循环中从会话中删除了块,如下所示。到目前为止,我似乎没有任何内存峰值:
def page_query(q):
while True:
r = False
for elem in q.limit(1000):
r = True
yield elem
if not r:
break
for chunk in page_query(query):
# Do something with the chunk if needed
session.delete(chunk)
session.commit()
长话短说,在删除具有大量集合的父对象时使用passive_deletes=True 似乎有很大帮助。页面查询在这种情况下似乎也能很好地工作,只是我必须取出偏移量,因为块正在从会话内联中删除。
【讨论】:
以上是关于如何在 SQLAlchemy 中使用空集合进行分页查询?的主要内容,如果未能解决你的问题,请参考以下文章