<commit_before>---
title: N+1 is a Rails feature, not a bug
author: <NAME>
published: true
summary: Stop and think before you reach for eager loading next time
description: In which we talk about how N+1 queries allow Rails developers to opt for Russian Doll caching to address performance bottlenecks.
pull_image: 'blog/stock/ladybug-pexels-photo.jpg'
series:
category: Code
tags:
  - Rails
---

One of the many mantras one learns on the path to "Rails enlightenment" is:

BEWARE OF THE N+1 QUERY!

### Everyone's favorite issue

To refresh, an N+1 query occurs when an association for a requested resource leads to N additional separate queries. Here's what an N+1 query looks like in the Rails log:

```sh
Started GET "/posts" for ::1 at 2016-09-18 07:26:15 -0400
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (2.2ms)  SELECT "posts".* FROM "posts" ORDER BY "posts"."published_at" DESC
  Author Load (0.2ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 90], ["LIMIT", 1]]
  Author Load (0.1ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 82], ["LIMIT", 1]]
  Author Load (0.1ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 83], ["LIMIT", 1]]
  #...
```

Do a quick search for [N+1 Rails](https://www.google.com/search?q=N%2B1+Rails&oq=N%2B1+Rails&aqs=chrome..69i57j69i60l2.2907j0j1&sourceid=chrome&ie=UTF-8) and all you see are "Problems", "Issues", etc. And just about every one of those posts will state that the *Silver Bullet* to solve this problem is Eager Loading. No joke, there is actually a gem called [`bullet`](https://github.com/flyerhzm/bullet) that will help resolve your N+1 issues with warnings and suggestions right in your logs to use eager loading where appropriate.

At some point, we've probably started to wonder why Rails just eager load for us.

### When gurus chat

Now consider this. Back in April, the author of [The Complete Guide to Rails Performance](https://www.railsspeed.com/) (check it out, it's awesome), [<NAME>](http://nateberkopec.com/) spoke with [DHH](https://twitter.com/dhh) about, ahem, Rails performance. [Not 5 minutes in](https://youtu.be/ktZLpjCanvg?t=4m27s), DHH says this:

> N+1 is a feature

WTF? But all those articles!

Here's the rest of what he said about it (emphasis mine):
<commit_msg>Copy edits<commit_after>---
title: N+1 is a Rails feature, not a bug
author: <NAME>
published: true
summary: Stop and think before you reach for eager loading next time
description: In which we talk about how N+1 queries allow Rails developers to opt for Russian Doll caching to address performance bottlenecks.
pull_image: 'blog/stock/ladybug-pexels-photo.jpg'
series:
category: Code
tags:
  - Rails
---

One of the many mantras one learns on the path to "Rails enlightenment" is:

BEWARE OF THE N+1 QUERY!

### Everyone's favorite issue

To refresh, an N+1 query occurs when an association for a requested resource leads to N additional separate queries. Here's what an N+1 query looks like in the Rails log where a `post` request is followed by N requests for their associated `authors`:

```sh
Started GET "/posts" for ::1 at 2016-09-18 07:26:15 -0400
Processing by PostsController#index as HTML
  Rendering posts/index.html.erb within layouts/application
  Post Load (2.2ms)  SELECT "posts".* FROM "posts" ORDER BY "posts"."published_at" DESC
  Author Load (0.2ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 90], ["LIMIT", 1]]
  Author Load (0.1ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 82], ["LIMIT", 1]]
  Author Load (0.1ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2  [["id", 83], ["LIMIT", 1]]
  #...
```

Do a quick search for [N+1 Rails](https://www.google.com/search?q=N%2B1+Rails&oq=N%2B1+Rails&aqs=chrome..69i57j69i60l2.2907j0j1&sourceid=chrome&ie=UTF-8) and all you see are "Problems", "Issues", etc. And just about every one of those posts will state that the *Silver Bullet* to solve this problem is Eager Loading. No joke, there is actually a gem called [`bullet`](https://github.com/flyerhzm/bullet) that will help resolve your N+1 issues with warnings and suggestions right in your logs to use eager loading where appropriate.

At some point, we've probably started to wonder why Rails just eager load for us.

### When gurus chat

Now consider this. Back in April, the author of [The Complete Guide to Rails Performance](https://www.railsspeed.com/) (check it out, it's awesome), [<NAME>](http://nateberkopec.com/) spoke with [DHH](https://twitter.com/dhh) about, ahem, Rails performance. [Not 5 minutes in](https://youtu.be/ktZLpjCanvg?t=4m27s), DHH says this:

> N+1 is a feature

WTF? But all those articles!

Here's the rest of what he said about it (emphasis mine):

{'fraction_non_alphanumeric': 0.12147064797887468, 'fraction_numerical': 0.030062969733902094, 'mean_word_length': 4.452934662236988, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 10, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1366678', 'n_tokens_mistral': 1703, 'n_tokens_neox': 1556, 'n_words': 662}