Exercise 3: A Real Three-Level N+1, Measured — Possible Solution ==================================================================== THE THIRD LEVEL ------------------------------ CREATE TABLE comments (id INTEGER PRIMARY KEY, body TEXT, post_id INTEGER) Extending the chapter's own authors/posts setup with 2 authors, 5 posts (all belonging to author 1), and 2 comments per post (10 comments total). NAIVE: LAZY-LOAD EVERY LEVEL, ONE QUERY AT A TIME ------------------------------------------------------------ authors = conn.execute("SELECT id, name FROM authors").fetchall() # 1 query for author_row in authors: posts = conn.execute( # 1 query PER author "SELECT id, title FROM posts2 WHERE author_id = ?", (author_row[0],) ).fetchall() for post_row in posts: comments = conn.execute( # 1 query PER post "SELECT id, body FROM comments WHERE post_id = ?", (post_row[0],) ).fetchall() QUERY COUNT, VERIFIED DIRECTLY AGAINST A REAL SQLITE DATABASE ------------------------------------------------------------------ 8 total queries Breaking that 8 down exactly: 1 (all authors) + 2 (one posts-query per author -- one for Ann, one for Bo, even though Bo has zero posts) + 5 (one comments-query per post, only for author 1's 5 real posts) = 8. EAGER: ONE BATCHED IN-CLAUSE QUERY PER LEVEL ------------------------------------------------------------ authors = conn.execute("SELECT id, name FROM authors").fetchall() # 1 query author_ids = [r[0] for r in authors] posts = conn.execute( # 1 query, batched f"SELECT id, title, author_id FROM posts2 WHERE author_id IN ({placeholders})", author_ids ).fetchall() post_ids = [r[0] for r in posts] comments = conn.execute( # 1 query, batched f"SELECT id, body, post_id FROM comments WHERE post_id IN ({placeholders2})", post_ids ).fetchall() QUERY COUNT, VERIFIED DIRECTLY ------------------------------------------------------------ 3 total queries Exactly one query per real level of the hierarchy -- authors, posts, comments -- regardless of how many rows exist at each level. WHY THIS GENERALIZES THE CHAPTER'S OWN TWO-LEVEL FINDING ------------------------------------------------------------------------ The chapter's own two-level example (posts -> authors) went from N+1 queries down to 2. This three-level version goes from a naive cost that grows with the total number of rows at every intermediate level (8, here, and genuinely larger with more authors or more posts per author) down to a fixed cost of exactly one query per level (3, here, regardless of how much data exists within each level) -- confirming Django's own prefetch_related() and SQLAlchemy's own selectinload() strategy, "one query per relationship, batched with IN," scales the identical way however many real levels of nested relationships a query actually needs to walk through. WHY THIS WORKS AS AN ANSWER ---------------------------- It extends the chapter's own real schema with a genuine third relationship level rather than only two, measures both the naive and eager query counts directly against a real SQLite database using the chapter's own CountingConnection class, and draws the real, general conclusion the numbers support: eager batching costs one query per level, not one query per row.