Phase 17 of 25 · Topic 17.4

SQLAlchemy Relationships: selectinload vs joinedload

1Concept

To prevent the fatal N+1 Query Problem, SQLAlchemy provides eager loading strategies: `selectinload()` loads related collections using a secondary `SELECT ... WHERE id IN (...)` query (ideal for 1-to-many); `joinedload()` uses SQL `LEFT OUTER JOIN` (ideal for many-to-1).

2Architecture Diagram

Lazy Loading (Anti-Pattern): 1 Query for Users + N queries for each User's Orders (N+1 Problem!)
selectinload (Best Practice): 1 Query for Users + 1 Query for Orders using IN (id1, id2...)

3Code Example

Python 3.12
# Demonstrating eager loading strategies
print("=== SQLAlchemy Eager Loading Strategies ===")
print("1. selectinload(User.orders):")
print("   - Emits: SELECT * FROM orders WHERE user_id IN (1, 2, 3...)")
print("   - Best for: One-to-Many and Many-to-Many relationships.")
print("2. joinedload(Order.user):")
print("   - Emits: SELECT * FROM orders LEFT JOIN users ON ...")
print("   - Best for: Many-to-One and One-to-One relationships.")

4Expected Output

=== SQLAlchemy Eager Loading Strategies ===
1. selectinload(User.orders):
   - Emits: SELECT * FROM orders WHERE user_id IN (1, 2, 3...)
   - Best for: One-to-Many and Many-to-Many relationships.
2. joinedload(Order.user):
   - Emits: SELECT * FROM orders LEFT JOIN users ON ...
   - Best for: Many-to-One and One-to-One relationships.

5Key Takeaways

  • Never use default lazy loading in async architectures; it will fail with `MissingGreenlet`.
  • `selectinload` avoids duplicate row data transfer overhead caused by cartesian products in joins.
  • Configure relationship loading in queries with `options(selectinload(User.orders))`.