1 min read

Detecting N+1 Queries in Production Logs

Visual guide to detecting ORM issues and fixing with eager loading
Street photograph by Stalin Pereira
Photo by Stalin Pereira

Your ORM Is Lying to You

Visualizing the N+1 performance killer.

The Innocent Code

  • The Loop — users = User.all(); foreach user: print user.address.city
  • The Expectation — One database query to get everything.
  • The Reality — One query for Users. Plus ONE query for each user to get the address.

The N+1 Mathematics

  • 1 Query — SELECT * FROM users (Returns 100 users).
  • N Queries — 100 x SELECT * FROM addresses WHERE user_id = ?.
  • Total — 101 queries for one page load. This kills the database.

The Fix: Eager Loading

  • The Instruction — Tell the ORM upfront what you need: .include('address').
  • The Result — The ORM does a JOIN or a WHERE IN clause.
  • Efficiency — Reduces 101 queries down to 2 queries.

Detection in Logs

  • Visual Pattern — Look for a wall of identical SELECT statements in your terminal.
  • Tools — Laravel Telescope, Django Debug Toolbar, or Rails Bullet.

When Lazy Loading is OK

  • Single Record — Fetching details for just one user (Profile Page).
  • Conditional — When the data is rarely accessed and heavy to fetch.

Summary: Fetch Smart

Do the weekly grocery shop (one big trip).

Don't treat your database like a convenience store (many small trips).

Check your query logs today.