Scale & Performance
Understanding Performance
Application
Relational DB
API
Files
NoSQL DB
External
Dependencies
Faster
Slower
Cache
RAM
How to optimise for this?
- Caching
- Avoid queries wherever possible
Big O Notation
- A way of understanding complexity in your code
- The greater the complexity the slower your code
O(1) - Same speed, no matter how big the input size
def first_element(array)
array.first
end
O(n) - Complexity gets bigger in proportion to the size of input
def print_elements(array)
array.each do |element|
# We have to run this line of
# code array.size times
puts element
end
end
O(n²) - Complexity proportional to the size of the input squared
def matching_values(array)
array.each do |element|
array.each do |other_element|
# We have to run this line of
# code array.size * array.size times
# so if the array has 5 elements,
# we run it 25 times
puts "array matches" if element == other_element
end
end
end
O(n) + 1 is the only one I've really needed
# 1 DB query
users = User.all
users.each do |user|
# This will do another `users.length` DB queries
# So if there are 50 users this will do 50 queries
puts user.blogs
end
# If n = users.length
# Total of n + 1 queries
Solution to n plus one
# 1 DB query
users = User.all
# 1 DB query
blogs = Blog.where("user_id IN ?", users)
users.each do |user|
# We still have to do this each time
# But it's much quicker to do this in RAM
# than go to the DB each time
puts blogs.find { |blog| blog.user_id == user }
end
# Total of 2 queries regardless of size of users.length
Scaling
- Vertical Scaling (bigger server)
- Horizontal Scaling (add more servers)
Scaling means keeping the behavior of an application the same as load (broadly, the number of users) increases
Optimising
By Leo Allen
Optimising
- 615