Tips for Writing Fast Rails: Part 2
Some time ago we wrote a couple of Tips for Writing Fast Rails . It was about time we wrote part two so here it is!
In this article we will focus on the use of ActiveRecord::Calculations . To show the difference in execution time between doing the math in the database vs. in Ruby we will use benchmark-ips . Keep in mind that the table used in these examples has thousands of records, so the difference should be quite noticeable.
Prefer ActiveRecord::Calculations#sum instead of Enumerable#sum
Usually in Rails applications we find many references to Enumerable::sum
for summing values. This is a common mistake because ActiveRecord::Calculations
provides a way to do this without loading a bunch of ActiveRecord
objects in memory. If you want to perform mathematical operations for a set of records following the Rails way, ActiveRecord::Calculations
is the best way to do them in the database.
Benchmark.ips do |x|
x.report("SQL sum") do
Loan.sum(:balance)
end
x.report("Ruby sum") do
Loan.sum(&:balance)
# Same as: Loan.all.map { |loan| loan.balance }.sum
end
x.compare!
end
# Comparison:
# SQL sum: 7.89 i/s
# Ruby sum: 0.03 i/s - 209.85x slower
Prefer ActiveRecord::Calculations#maximum instead of Enumerable#max
As we explained above, to perform better with calculations you should use ActiveRecord::Calculations
methods whenever is possible.
Benchmark.ips do |x|
x.report("SQL max") do
Loan.maximum(:amount)
end
x.report("Ruby max") do
Loan.pluck(:amount).max
end
x.compare!
end
# Comparison:
# SQL max: 541.9 i/s
# Ruby max: 0.5 i/s - 1113.47x slower
Prefer ActiveRecord::Calculations#minimum instead of Enumerable#min
Benchmark.ips do |x|
x.report("SQL min") do
Loan.minimum(:amount)
end
x.report("Ruby min") do
Loan.pluck(:amount).min
end
x.compare!
end
# Comparison:
# SQL min: 533.3 i/s
# Ruby min: 0.5 i/s - 1017.21x slower
Conclusion
As you can see, changing the way that you solve the problem can have significant performance improvements. Don’t forget to take a look at the ActiveRecord::Calculations
documentation to see all the available methods.