Orm 由混合属性生成的低效相关子查询
我有一个简单的数据库模型Orm 由混合属性生成的低效相关子查询,orm,sqlalchemy,Orm,Sqlalchemy,我有一个简单的数据库模型 class Account(ModelBase): name = Column(String(127), nullable=False) @hybrid_property def balance(self): return sum(imap(operator.attrgetter("amount"), self.transactions)) @balance.expression def balance(sel
class Account(ModelBase):
name = Column(String(127), nullable=False)
@hybrid_property
def balance(self):
return sum(imap(operator.attrgetter("amount"), self.transactions))
@balance.expression
def balance(self):
return select(
[func.sum(Transaction.amount)]
).where(
Transaction.account_id == self.id
).label("balance")
class Transaction(ModelBase):
amount = Column(Integer, nullable=False)
account_id = Column(Integer,
ForeignKey(Account.id, ondelete='CASCADE'),
nullable=False)
account = relationship(Account,
backref=backref("transactions",
cascade="all, delete-orphan"))
如果我随后执行以下查询
session.query(Account).filter(Account.balance < 0)
如何使简单的混合查询更高效,这样就不必显式地组合更高效的查询?我必须使用还是有更简单的方法
独立示例:
#!/usr/bin/env python2
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import sessionmaker, relationship, backref
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, select, func
Base = declarative_base()
class Account(Base):
__tablename__ = 'account'
id = Column(Integer, primary_key=True)
name = Column(String(127), nullable=False)
@hybrid_property
def balance(self):
return sum(imap(operator.attrgetter("amount"), self.transactions))
@balance.expression
def balance(self):
return select(
[func.sum(Transaction.amount)]
).where(
Transaction.account_id == self.id
).label("balance")
class Transaction(Base):
__tablename__ = 'transaction'
id = Column(Integer, primary_key=True)
amount = Column(Integer, nullable=False)
account_id = Column(Integer,
ForeignKey(Account.id, ondelete='CASCADE'),
nullable=False)
account = relationship(Account,
backref=backref("transactions",
cascade="all, delete-orphan"))
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
print '\n{:=^80}'.format('actual query')
print session.query(Account).filter(Account.balance > 0)
print '\n{:=^80}'.format('desired query')
print session.query(Account).join(Transaction).group_by(Account).having(func.sum(Transaction.amount) > 0)
你能发布一个简单的自包含测试脚本吗?谢谢,这很难
Seq Scan on account (cost=0.00..36631458.18 rows=3543 width=38)
Filter: ((SubPlan 1) < 0)
SubPlan 1
-> Aggregate (cost=3446.66..3446.67 rows=1 width=4)
-> Seq Scan on transaction (cost=0.00..3446.60 rows=25 width=4)
Filter: (account_id = account.id)
SELECT account.id AS account_id, account.name as account_name
FROM account JOIN transaction on transaction.account_id = account.id
GROUP BY account.id
HAVING sum(transaction.amount) < 0;
GroupAggregate (cost=22488.79..27353.75 rows=10628 width=38)
Filter: (sum(transaction.amount) > 0)
-> Merge Join (cost=22488.79..26258.66 rows=192448 width=38)
Merge Cond: (account.id = transaction.account_id)
-> Index Scan using account_pkey on account (cost=0.00..376.68 rows=10628 width=34)
-> Materialize (cost=22488.75..23450.99 rows=192448 width=8)
-> Sort (cost=22488.75..22969.87 rows=192448 width=8)
Sort Key: transaction.account_id
-> Seq Scan on transaction (cost=0.00..2965.48 rows=192448 width=8)
#!/usr/bin/env python2
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import sessionmaker, relationship, backref
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, select, func
Base = declarative_base()
class Account(Base):
__tablename__ = 'account'
id = Column(Integer, primary_key=True)
name = Column(String(127), nullable=False)
@hybrid_property
def balance(self):
return sum(imap(operator.attrgetter("amount"), self.transactions))
@balance.expression
def balance(self):
return select(
[func.sum(Transaction.amount)]
).where(
Transaction.account_id == self.id
).label("balance")
class Transaction(Base):
__tablename__ = 'transaction'
id = Column(Integer, primary_key=True)
amount = Column(Integer, nullable=False)
account_id = Column(Integer,
ForeignKey(Account.id, ondelete='CASCADE'),
nullable=False)
account = relationship(Account,
backref=backref("transactions",
cascade="all, delete-orphan"))
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
print '\n{:=^80}'.format('actual query')
print session.query(Account).filter(Account.balance > 0)
print '\n{:=^80}'.format('desired query')
print session.query(Account).join(Transaction).group_by(Account).having(func.sum(Transaction.amount) > 0)