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 bottleneck | fix |
|---|---|
| N+1 queries | includes; strict_loading; Bullet |
| missing indexes | add_index in migrations (algorithm: :concurrently on Postgres); check plans |
| slow views | fragment caching; fewer partials in loops |
| large JSON responses | pagination (pagy); select only needed columns; faster serializers |
| memory growth in Puma | jemalloc, YJIT memory settings, puma_worker_killer as a last resort |