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" во всех отношениях, но первые 2 запроса все еще присутствуют. Я хочу избавиться от них. Окончательный запрос может использовать соединения, но это должен быть единственный запрос.
Это игрушечный пример, но в реальном проекте слишком много таких запросов-паразитов, когда я просто обращаюсь к полям отношений. Мой проект выполняет много небольших запросов (в основном с одной записью), поэтому производительность очень низкая :(