Part 8 · 1 chapters · ~8 min

Performance

Measuring with rack-mini-profiler, stackprof, vernier and memory_profiler, N+1 elimination, database indexes and query plans from Rails, caching (fragment, Russian doll, low-level with Solid Cache or Redis), pagination, JSON rendering costs, YJIT, and jemalloc.

9

Where Rails apps spend time

code
# Gemfile (development)
gem "rack-mini-profiler"; gem "stackprof"; gem "memory_profiler"; gem "bullet"
# ?pp=flamegraph on any page (rack-mini-profiler + stackprof) shows a flame graph of that request

# caching: fragment and low-level
<% cache [account, account.postings.maximum(:updated_at)] do %> ... <% end %>      # Russian doll caching
rate = Rails.cache.fetch("rate:#{pair}", expires_in: 30.seconds) { Rates.fetch(pair) }  # Solid Cache or Redis

Transfer.where(account: acct).explain        # the query plan from Rails
usual bottleneckfix
N+1 queriesincludes; strict_loading; Bullet
missing indexesadd_index in migrations (algorithm: :concurrently on Postgres); check plans
slow viewsfragment caching; fewer partials in loops
large JSON responsespagination (pagy); select only needed columns; faster serializers
memory growth in Pumajemalloc, YJIT memory settings, puma_worker_killer as a last resort