Is Query Readability Costing Efficiency?
Louis Davis
Retrieving all the information you need from a database for your web page could be imagined like you're doing some cooking. Initially, you need to get all the ingredients from your cupboard. There are a few ways of going about this.
You could go back and forth to the cupboard multiple times with a short, scannable ingredient list
However, because your list is easy to read and scan, it doesn't include specific details about each ingredient you want to use. Once you have everything out, you'd realise you only need the self-raising flour, not the plain flour you got out, but now that extra flour is using up your counter space.
You could make your ingredient list more detailed
Now each cupboard trip gets precisely the ingredients you need. You avoid filling your counter space with unnecessary items while saving time when you look through the ingredients later. However, you still need to spend lots of time walking back and forth.
You could keep your list simple but make one trip
Grab everything you could possibly need and worry about sorting through it later. Now you've saved time with one trip. Still, your counter is overflowing with unnecessary items, which you must sort through all over again to find what you actually need.
Or, you could make your list detailed and only make one trip
Now you've got everything you need, all at once, and all it took was a bit of pre-planning. You haven't made any extra trips, you have precisely what you need, and you still have a lot of counter space to go about your work.
Now, use that approach for writing queries
Think of the trips back and forth to the cupboard as a database connection, how you break down your lists and the extra details as your query, and your counter as the memory.
The crucial part of how you retrieve data from your database is the query you write, so if you focus on keeping it simple and separating what you need into multiple queries to make the code more readable, it could be costing you versus a much longer query with specific conditionals for what you need.
For example, on a recent project, we had the following readable but slow query;
User.where(state: 'approved')
.order(created_at: :desc)
.includes(:org_invoices)
.limit(10)
# User Load (5.2ms) ...
# UserOrganisation Load (4.7ms) ...
# Organisation Load (2.4ms) ...
# Invoice Load (6.1ms) ...
# Total: 18.4ms
Due to the multiple table relationships, the query became less performant as the project scaled (and the cupboard analogy becomes even harder to contextualise). So, we rewrote the query to perform a single table join so all the data we'd need was in one place.
User.joins(:org_invoices)
.where(state: :approved)
.order('users.created_at desc')
.limit(10)
.select('DISTINCT users.*')
# User Load (11.0ms) ...
# Total: 11.0ms
Making more complex or specific database queries can have drawbacks. If you have 100 objects in your table and want to select 90 of them, should you specify the ids of the objects even if they can be expressed in a simple range, or get all of them? Suppose it's a query used only once, like for data migrations. Is it worth an hour rewriting a series of queries when it will only save you a few seconds overall?
Account.where(id: [1..90]) # Account Load (2.1ms)
Account.limit(90) # Account Load (1.4ms)
Account.all # Account Load (1.1ms)
In Conclusion
While over-simplification may save you time reading, understanding what you need could take extra time, and the overall performance may be slower. However, being overly specific when you don't need to could result in you over-engineering a problem that doesn't warrant it. A chosen approach for writing queries should be arrived at on a case-by-case basis rather than with the mindset that one rule fits.
Martin Dick
Co-Founder, mmtm
Need help making your Rails app faster?
For more than 10 years, we've helped businesses build, improve and support Ruby on Rails applications, including products used by hundreds of thousands of users.
If slow queries, memory bloat or heavy pages are making your app harder to use, I'd be happy to help you spot the quick wins!
Schedule a callFrequently Asked Questions
How can I improve database query performance in Rails?
A good first step is to check which pages make the most database calls or load more records than they need. In Rails, that usually means reviewing Active Record queries, joins, includes, select, pluck, indexing and logs. The best fix depends on whether the bottleneck is query count, memory use or slow SQL.
Is one larger query always faster than several smaller queries?
Not always! One well-planned query can reduce database round trips and memory use, but a bigger query is not automatically better. If it is hard to understand, rarely used, or only saves a tiny amount of time, the extra complexity may not be worth it. Measure the impact before refactoring.
How do I know if slow queries are affecting my Rails application?
Common signs include slow-loading pages, timeout errors, high memory use, database spikes, or features that become noticeably slower as the number of records grows. Rails logs, database monitoring and performance profiling can help show whether the issue is query structure, missing indexes, eager loading, or too much data being loaded at once.
Not Sure What To Read Next? Here's What We Recommend...
- Performance Optimisation
- Web Development
- Ruby on Rails
- Database Queries