python - 在 SQLALchemy 的一对一关系中进行了太多选择

标签 python sql database performance sqlalchemy

import sqlalchemy as db
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Entity(Base):
    __tablename__ = 'entity'
    id = db.Column(db.Integer, primary_key=True, index=True)
    a = db.Column(db.Integer, index=True)
    b = db.Column(db.Integer)

    foos = relationship('Foo')


class Foo(Base):
    __tablename__ = 'foo'
    id = db.Column(db.Integer, primary_key=True, index=True)

    entity_id = db.Column(db.Integer, db.ForeignKey('entity.id'))

    entity = relationship('Entity', uselist=False)
    bars = relationship('Bar')


class Bar(Base):
    __tablename__ = 'bar'
    id = db.Column(db.Integer, primary_key=True, index=True)

    foo_id = db.Column(db.Integer, db.ForeignKey('foo.id'))

    foo = relationship('Foo', uselist=False)

engine = db.create_engine('sqlite:///:memory:', echo=False)
session = sessionmaker(bind=engine)()
Base.metadata.create_all(engine)

def relationship_optimizing():
    engine.echo = True
    entity = Entity(a=1000000, b=10000000000)
    foo = Foo(entity=entity)
    bar = Bar(foo=foo)
    session.add_all([entity, foo, bar])
    session.commit()
    bla = session.query(Entity).filter_by(id=bar.foo.entity_id).one()
    session.commit()

relationship_optimizing()

当我尝试使用一对一关系访问链访问某些对象时,即使没有必要进行查询,每个点操作都会得到一个 SELECT。

看代码。当我尝试获取对象“bla”时,SQLAlchemy 生成 3 个查询:

SELECT bar.id AS bar_id, bar.foo_id AS bar_foo_id 
FROM bar 
WHERE bar.id = 1

SELECT foo.id AS foo_id, foo.entity_id AS foo_entity_id 
FROM foo 
WHERE foo.id = 1

SELECT entity.id AS entity_id, entity.a AS entity_a, entity.b AS entity_b 
FROM entity 
WHERE entity.id = 1

我尝试在所有关系中使用 lazy="joined"和 lazy="subquery",但前两个查询仍然存在。我想摆脱他们。最终查询可能会使用连接,但它应该是唯一的一个查询。

这是一个玩具示例,但在实际项目中,当我只是访问关系字段时,有太多类似的寄生查询。 我的项目做了很多小查询(主要是一条记录)所以性能真的很慢:(

最佳答案

问题是您在调用 add_all 之后提交。提交后,SQLAlchemy 无法知道其他事务没有修改与您的对象对应的行,因此它会“忘记”它们的所有属性,直到您下次使用它们为止。

没有理由在工作进行到一半时进行提交,这从一开始就违背了事务的目的。如果您需要做的只是让 id 填充到您的对象上,请使用 session.flush(),它会更新数据库以匹配您的对象 — 没有 promise 。

session.commit() 只是碰巧解决了这个问题,因为它(必须)首先刷新,但出于某种原因,当您只需要自动 key 时,提交而不是刷新已成为伪造的建议.

关于python - 在 SQLALchemy 的一对一关系中进行了太多选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30740517/

相关文章:

sql - SQL Server 中的 BETWEEN

mysql - 如何存储在数据库中有用的多项选择?

database - iODBC 在 Mac OSX 10.6.4 下不工作

python - 使用带有特殊字符的正则表达式在 python 中查找匹配项

python - 打印带有 "#"符号的高度列表

python - 使用 __main__ 方法导入 python

mysql - Bacula使用sql查询搜索文件

python - 使用 Python 附加 geoJSON 功能?

sql - 在 PostgreSQL 中处理竞争条件

sql - 如何获取不包含在分组依据中的列的值(SQL Server)