Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reducing n+1 queries using the Bullet and RSpec gems

What is an effective way to use the Bullet Gem with RSpec? Right now I feel if I use it with my current unit test framework I get a lot of notifications or failures of tests because of n+1 queries within the tests themselves that are not related to what happens in my production application, such as checking a value or association. As such, fixing the n+1 failures does not require setting anything on my controllers or models, rather it requires setting something in my test setup to not throw that particular error and I see no real performance improvement on my application.

like image 817
Ben Nelson Avatar asked Jan 09 '23 16:01

Ben Nelson


1 Answers

The most effective way is not at all. There may be some legitimate advantages to reducing n+1 queries in tests, most obviously to speed up overall execution time. It is quite possible, however, that you are either testing too much or making less significant gains than what is possible. I also usually find it unappealing to write additional code to help prop up tests, rather than to contribute to the overall value of the application.

Please allow me to propose an alternate use of your time. Only unit test to the absolute minimum of your comfort level. I personally like to focus on complex methods involving validation related issues and money or other math, you may have different priorities. Drawing the line will free up a whole bunch of time writing the most useless and fragile part of your test suite that will occupy the majority of your maintenance budget.

Now, what to do will all of your extra time? Don't worry, we'll find something for you to do... You can start by writing some acceptance tests, particularly for the areas that use the objects that you just dropped a whole bunch of unit tests for. Now your n+1 warnings are actually coming from the same spot they will when the user hits the page. Now you can go on to remove all of the n+1 queries.

But wait! Don't do that either. Instead, spend a good deal less time setting up your relationships to use the touch option. Then, when a child object gets updated, the parent will be updated, too. What the hell does this have to do with n+1 queries, you might be wondering. It seems like we're just adding queries...

That's where the Russian doll caching comes in. Adding this, and properly testing it, will consume the freed up unit testing and n+1 elimination time (and then some, if you're not careful). The nice thing is that it is way more "real world", much more resilient to insignificant or irrelevant implementation changes in your models and whatnot, and a huge performance boost to your application well beyond what eliminating every n+1 query by eagerly loading everything up front might have provided. You will want to move as much as possible into nested caching and load everything as lazily as humanly possible, to take full advantage of this method.

Long live n+1!

like image 50
Brad Werth Avatar answered Jan 18 '23 12:01

Brad Werth