我正在尝试找到一种内存有效的方法来执行分页查询以测试空集合,但似乎无法弄清楚如何在大型数据库上有效地进行此操作。表格布局使用具有双向backref的关联对象。它与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
然而,由于内存使用量仍然很高,因此这似乎不适用于空集合查询。有没有办法对像这样的空集合进行分页查询?
答案 0 :(得分:1)
我发现这里遗漏了一些东西。对空块的查询似乎基本上没问题。我看到的内存使用率峰值是在实际成员本身被删除时,在代码前面的几行查询。
member = session.query(Member).filter(Member.name == membername).one()
session.delete(member)
根据文档,会话(默认情况下)只能删除加载到会话/内存中的对象。当成员被删除时,它将加载它的所有关联,以便按照级联规则删除它们。需要做的是使用passive deletes来绕过关联加载。
我补充说:
passive_deletes=True
到成员类的关联关系,并且:
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似乎有很大帮助。页面查询在这种情况下似乎也很好用,因为我必须取出偏移量,因为从内联会话中删除了块。