2013-03-21 52 views
2

考虑下面的语句:的SQLAlchemy:joinedload +极限

p = db.query(Profile).options(joinedload('*')).filter_by(id=p.id).limit(1).one() 

我会得到一个子查询+联接,而不是一个 “纯” 加盟:

SELECT [...] 
FROM (SELECT profile.id AS profile_id, ... 
FROM profile 
WHERE profile.id = %(id_1)s 
LIMIT %(param_1)s) AS anon_1 LEFT OUTER JOIN city AS city_1 ON city_1.id = anon_1.profile_city LEFT OUTER JOIN country AS country_1 ON country_1.id = city_1.country LEFT OUTER JOIN state AS state_1 ON country_1.id = state_1.country LEFT OUTER JOIN state AS state_2 ON state_2.id = city_1.state LEFT OUTER JOIN country AS country_2 ON country_2.id = state_2.country LEFT OUTER JOIN state AS state_3 ON state_3.id = city_1.state LEFT OUTER JOIN country AS country_3 ON country_3.id = state_3.country LEFT OUTER JOIN starred AS starred_1 ON anon_1.profile_id = starred_1.star LEFT OUTER JOIN profiletext AS profiletext_1 ON anon_1.profile_id = profiletext_1.profile LEFT OUTER JOIN starred AS starred_2 ON anon_1.profile_id = starred_2.idprofile LEFT OUTER JOIN photo AS photo_1 ON anon_1.profile_id = photo_1.profile LEFT OUTER JOIN gps AS gps_1 ON anon_1.profile_id = gps_1.idprofile 

但我真正需要的是:

SELECT ... 
FROM profile LEFT OUTER JOIN city AS city_1 ON city_1.id = profile.city LEFT OUTER JOIN country AS country_1 ON country_1.id = city_1.country LEFT OUTER JOIN state AS state_1 ON country_1.id = state_1.country LEFT OUTER JOIN state AS state_2 ON state_2.id = city_1.state  
LEFT OUTER JOIN country AS country_2 ON country_2.id = state_2.country LEFT OUTER JOIN state AS state_3 ON state_3.id = city_1.state LEFT OUTER JOIN country AS country_3 ON country_3.id = state_3.country LEFT OUTER JOIN starred AS starred_1 ON profile.id = starred_1.star LEFT OUTER JOIN profiletext AS profiletext_1 ON profile.id = profiletext_1.profile LEFT OUTER JOIN starred AS starred_2 ON profile.id = starred_2.idprofile LEFT OUTER JOIN photo AS photo_1 ON profile.id = photo_1.profile LEFT OUTER JOIN gps AS gps_1 
ON profile.id = gps_1.idprofile                                                  
WHERE profile.id = 4 
limit 1; 

即没有子查询。

数据库:在PostgreSQL 9.2

+0

你使用的是哪个数据库? – 2013-03-21 16:42:13

+0

postgresql 9.2。 – jbastos 2013-03-21 16:47:30

回答

2

这似乎是根据The Zen of Eager Loading

当使用加入预先加载,如果查询包含 影响的行外返回加入改性剂预期的行为,这样的在使用 DISTINCT,LIMIT,OFFSET或同等语句时,完成的语句是 首先被包装在子查询中,并且专用于 的连接被加入预先加载的子查询。 SQLAlchemy的加入 急于加载走多余的一英里,然后进一步十英里,到 绝对保证它不会影响查询的最终结果, 只有收集方式和相关对象被加载,不管 什么格式该查询是。

我意识到这是一个老问题,但是有没有原因生成的SQL不起作用?

+0

这是否意味着如果在查询中某处存在具有限制/ distinct/offset与查询的查询中某处的查询,那么该连接的数据被视为子查询? – adarsh 2014-07-21 11:42:31

+0

看来是这样,是的。我不确定sqlalchemy的内部是否将它转换为[subqueryload](http://docs.sqlalchemy.org/en/latest/orm/loading.html#sqlalchemy.orm.subqueryload),但似乎就像它有相同的结果。 – Ben 2014-07-22 18:03:37