contains_eager 和joinedload 之间的SQLAlchemy 区别

Igo*_*mar 4 python sql sqlalchemy

SQLAlchemycontains_eagerjoinedload. 我阅读了关于 contains_eager的手册,以及关于 joinload 的手册。它们都可用于加载一对多相关行或多对一。

他们正在生成相同的 sql:

query = session.query(User).\
    outerjoin(adalias, User.addresses).\
    options(contains_eager(User.addresses, alias=adalias)).all()

...

SELECT
    users.user_id AS users_user_id,
    users.user_name AS users_user_name,
    adalias.address_id AS adalias_address_id,
    adalias.user_id AS adalias_user_id,
    adalias.email_address AS adalias_email_address,
    (...other columns...)
FROM users
LEFT OUTER JOIN email_addresses AS email_addresses_1
ON users.user_id = email_addresses_1.user_id


>>> jack = session.query(User).\
... options(joinedload(User.addresses)).\
... filter_by(name='jack').all()

SELECT
    addresses_1.id AS addresses_1_id,
    addresses_1.email_address AS addresses_1_email_address,
    addresses_1.user_id AS addresses_1_user_id,
    users.id AS users_id, users.name AS users_name,
    users.fullname AS users_fullname,
    users.password AS users_password
FROM users
LEFT OUTER JOIN addresses AS addresses_1
    ON users.id = addresses_1.user_id
WHERE users.name = ?
['jack']
Run Code Online (Sandbox Code Playgroud)

有人可以展示更具体的代码示例吗?

Ilj*_*ilä 6

不要忘记多对多和一对一。不同之处在于,contains_eager()您可以向 SQLA 指示一个或多个应用于填充关系的现有连接。通过这种方式,您还可以使用过滤后的子集进行填充

joinedload() on the other hand goes to great lengths to make the joins required for populating entirely transparent and they should not affect the outcome of the original query, as is explained in The Zen of Joined Eager Loading. In other words you cannot use the joined relations for filtering etc.

  • 值得一提的是:你不应该使用 `contains_eager()` 或 `joinedload` 来表示 1-N 或 NN 关系。这是因为 SQL 结果会产生一侧或两侧数据的乘法。对于 1-N 或 NN 关系,最好使用“selectinload”或“subqueryload”。 (7认同)
  • 确实如此,并且通常选择两者中的一个,但是(据我所知)它们不允许过滤填充 SQLA 中关系的相关实体。所以这是一种“选择你的毒药”的情况,以防你需要这样做。希望过滤后的集合足够小,以便 1 侧的重复并不重要。 (2认同)
  • 同意,对于少量数据通常并不重要,但是当有人执行多次连接加载并且数据库返回的输出比整个数据库大 25 倍时,我是见证人:) (2认同)