我认为您可以使用 acolumn_property
将最新值作为Entities
实例的属性与其他列映射属性一起加载:
from sqlalchemy import select
from sqlalchemy.orm import column_property
class Entities(Base):
...
value = column_property(
select([EntityHistory.value]).
where(EntityHistory.entity_id == id). # the id column from before
order_by(EntityHistory.timestamp.desc()).
limit(1).
correlate_except(EntityHistory)
)
子查询当然也可以在查询中使用,而不是column_property
.
query = session.query(
Entities,
session.query(EntityHistory.value).
filter(EntityHistory.entity_id == Entities.id).
order_by(EntityHistory.timestamp.desc()).
limit(1).
label('value')
)
性能自然取决于适当的索引:
Index('entityhistory_entity_id_timestamp_idx',
EntityHistory.entity_id,
EntityHistory.timestamp.desc())
在某种程度上,这仍然是您可怕的 N+1,因为查询每行使用一个子查询,但它隐藏在到数据库的单次往返中。
另一方面,如果不需要将value作为属性,则在 Postgresql 中,您可以使用DISTINCT ON ... ORDER BY查询加入以获取最新值:Entities
values = session.query(EntityHistory.entity_id,
EntityHistory.value).\
distinct(EntityHistory.entity_id).\
# The same index from before speeds this up.
# Remember nullslast(), if timestamp can be NULL.
order_by(EntityHistory.entity_id, EntityHistory.timestamp.desc()).\
subquery()
query = session.query(Entities, values.c.value).\
join(values, values.c.entity_id == Entities.id)
尽管在使用虚拟数据的有限测试中,如果每个实体都有值,则子查询作为输出列总是以显着的优势击败连接。另一方面,如果有数百万个实体和大量缺失的历史值,那么 LEFT JOIN 会更快。我建议对您自己的数据进行测试,哪个查询更适合您的数据。对于单个实体的随机访问,假设索引已到位,相关子查询会更快。对于批量提取:测试。