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/