Skip to main content
 首页 » 编程设计

python之如何在 SQLAlchemy 中使用空集合进行分页查询

2025年05月04日26grandyang

我正在尝试寻找一种节省内存的方法来执行分页查询以测试空集合,但似乎无法弄清楚如何在大型数据库上有效地执行此操作。表格布局使用具有双向反向引用的关联对象。它与 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) 

如果删除成员(member),会级联删除该成员(member)的关联。但是, block 对象将在数据库中被孤立。要删除孤立 block ,我可以使用如下查询测试空集合:

session.query(Chunk).filter(~Chunk.assoc.any()) 

然后删除 block :

query.delete(synchronize_session=False) 

但是,如果关联表和 block 表很大,则查询或子查询似乎加载了所有内容并且内存激增。

我已经看到使用分页查询来限制标准查询的内存使用的概念 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 

然而,这似乎不适用于空集合查询,因为内存使用率仍然很高。有没有办法对这样的空集合进行分页查询?

请您参考如下方法:

我发现这里缺少一些东西。对空 block 的查询似乎基本没问题。我看到的内存使用率峰值来自代码中几行前的查询,当时实际成员本身已被删除。

member = session.query(Member).filter(Member.name == membername).one() 
session.delete(member) 

根据文档, session (默认情况下)只能删除加载到 session /内存中的对象。当成员被删除时,它将加载它的所有关联,以便根据级联规则删除它们。需要发生的是必须使用 passive deletes 绕过关联加载。 .

我补充说:

passive_deletes=True 

Member类的关联关系和:

ondelete='CASCADE' 

关联类的member_id 外键。我正在使用 SQLite3 并根据 docs 添加了引擎连接事件的外键支持.

关于孤立 block ,而不是使用 query.delete 方法批量删除 block 。我使用了一个不包含偏移量的页面查询,并在循环中从 session 中删除了 block ,如下所示。到目前为止,我似乎没有任何内存峰值:

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 似乎有很大帮助。页面查询在这种情况下似乎也能很好地工作,只是我必须取出偏移量,因为 block 正在从 session 内联中删除。