2

我正在尝试找到一种内存有效的方法来执行分页查询以测试空集合,但似乎无法弄清楚如何在大型数据库上有效地执行它。表格布局使用具有双向反向引用的关联对象。它与文档非常相似。

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)

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

我在这里看到了使用分页查询来限制标准查询的内存使用的概念:

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

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

4

1 回答 1

1

我发现这里缺少一些东西。空块的查询似乎大部分都可以。我看到的内存使用高峰来自代码中前几行的查询,当时实际成员本身已被删除。

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

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

我补充说:

passive_deletes=True

到Member类的关联关系和:

ondelete='CASCADE'

到 Association 类的 member_id 外键。我正在使用 SQLite3,并根据文档添加了外键支持和引擎连接事件。

关于孤立块,而不是使用 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 似乎有很大帮助。页面查询在这种情况下似乎也能很好地工作,只是我不得不取出偏移量,因为块正在从会话内联中删除。

于 2012-12-02T15:47:03.503 回答