$npx -y skills add ThibautBaissac/rails_ai_agents --skill performance-optimizationIdentifies and fixes Rails performance issues including N+1 queries, slow queries, and memory problems. Use when optimizing queries, fixing N+1 issues, improving response times, or when user mentions performance, slow, optimization, or Bullet gem. WHEN NOT: Caching-specific patte
| 1 | # Performance Optimization for Rails 8 |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Performance optimization focuses on: |
| 6 | - N+1 query detection and prevention |
| 7 | - Query optimization |
| 8 | - Memory management |
| 9 | - Response time improvements |
| 10 | - Database indexing |
| 11 | |
| 12 | ## Quick Start |
| 13 | |
| 14 | ```ruby |
| 15 | # Gemfile |
| 16 | group :development, :test do |
| 17 | gem 'bullet' # N+1 detection |
| 18 | gem 'rack-mini-profiler' # Request profiling |
| 19 | gem 'memory_profiler' # Memory analysis |
| 20 | end |
| 21 | ``` |
| 22 | |
| 23 | ## N+1 Query Detection and Prevention |
| 24 | |
| 25 | N+1 queries occur when code loads a collection then makes a separate query for each associated record. The Bullet gem detects these automatically. Fix them with eager loading via `includes`, `preload`, or `eager_load`. |
| 26 | |
| 27 | ### Eager Loading Decision Table |
| 28 | |
| 29 | | Method | Use When | |
| 30 | |--------|----------| |
| 31 | | `includes` | Most cases (Rails chooses best strategy) | |
| 32 | | `preload` | Forcing separate queries, large datasets | |
| 33 | | `eager_load` | Filtering on association, need single query | |
| 34 | | `joins` | Only need to filter, don't need association data | |
| 35 | |
| 36 | Key patterns: Bullet configuration, eager loading methods, scoped eager loading, counter caches, N+1 specs with query count assertions. |
| 37 | |
| 38 | See [references/n-plus-one.md](references/n-plus-one.md) for all code examples and patterns. |
| 39 | |
| 40 | ## Query Optimization |
| 41 | |
| 42 | Optimize queries by selecting only needed columns, using batch processing for large datasets, and choosing efficient existence checks. |
| 43 | |
| 44 | ### Key Patterns |
| 45 | |
| 46 | | Pattern | Bad | Good | |
| 47 | |---------|-----|------| |
| 48 | | Column selection | `User.all.map(&:name)` | `User.pluck(:name)` | |
| 49 | | Large iterations | `Event.all.each { ... }` | `Event.find_each { ... }` | |
| 50 | | Existence checks | `.any?` / `.present?` | `.exists?` | |
| 51 | | Collection size | `.length` (loads all) | `.size` (smart) | |
| 52 | |
| 53 | ### Database Indexing |
| 54 | |
| 55 | Add indexes for: foreign keys, columns in WHERE/ORDER BY/JOIN clauses, and unique constraints. Use composite indexes for multi-column queries. Use partial indexes for filtered subsets. |
| 56 | |
| 57 | ### Query Analysis |
| 58 | |
| 59 | Use `Event.where(...).explain(:analyze)` to inspect query plans. Set up slow query logging via `ActiveSupport::Notifications` to catch queries over a threshold. |
| 60 | |
| 61 | See [references/query-optimization.md](references/query-optimization.md) for all code examples and patterns. |
| 62 | |
| 63 | ## Memory Management and Profiling |
| 64 | |
| 65 | Use `memory_profiler` to detect memory issues. Prefer `pluck` over loading full AR objects, use `find_each` for streaming, and use `update_all` / `in_batches` for bulk operations. |
| 66 | |
| 67 | ### Rack Mini Profiler |
| 68 | |
| 69 | Provides per-request profiling in development. Shows query count, timing, and flamegraphs (with `stackprof` gem). Access via the profiler badge or `?pp=flamegraph`. |
| 70 | |
| 71 | See [references/memory-and-profiling.md](references/memory-and-profiling.md) for all code examples and patterns. |
| 72 | |
| 73 | ## Quick Fixes Reference |
| 74 | |
| 75 | | Problem | Solution | |
| 76 | |---------|----------| |
| 77 | | N+1 on belongs_to | `includes(:association)` | |
| 78 | | N+1 on has_many | `includes(:association)` | |
| 79 | | Slow COUNT | Add counter_cache | |
| 80 | | Loading all columns | Use `select` or `pluck` | |
| 81 | | Large dataset iteration | Use `find_each` | |
| 82 | | Missing index on FK | Add index on `*_id` columns | |
| 83 | | Slow WHERE clause | Add index on filtered column | |
| 84 | | Loading unused associations | Remove from `includes` | |
| 85 | |
| 86 | ## Performance Checklist |
| 87 | |
| 88 | - [ ] Bullet enabled in development/test |
| 89 | - [ ] No N+1 queries in critical paths |
| 90 | - [ ] Foreign keys have indexes |
| 91 | - [ ] Counter caches for frequent counts |
| 92 | - [ ] Eager loading in controllers |
| 93 | - [ ] Batch processing for large datasets |
| 94 | - [ ] Query analysis for slow endpoints |
| 95 | |
| 96 | ## Workflow |
| 97 | |
| 98 | 1. **Detect** -- Enable Bullet, run specs, check Rack Mini Profiler |
| 99 | 2. **Analyze** -- Use `explain(:analyze)`, check slow query logs, profile memory |
| 100 | 3. **Fix** -- Apply the appropriate pattern from the reference files |
| 101 | 4. **Verify** -- Re-run specs, confirm query counts, check profiler |
| 102 | |
| 103 | ## Reference Files |
| 104 | |
| 105 | - [references/n-plus-one.md](references/n-plus-one.md) -- N+1 detection, eager loading methods, Bullet config, counter caches, testing patterns |
| 106 | - [references/query-optimization.md](references/query-optimization.md) -- Column selection, batch processing, indexing strategies, EXPLAIN analysis, slow query logging |
| 107 | - [references/memory-and-profiling.md](references/memory-and-profiling.md) -- Memory profiler usage, memory-efficient patterns, Rack Mini Profiler setup, deployment checklist |