rails/learn
Databases in Production
Eight lessons on running Postgres under a Rails app. The first four build the foundations: reading query plans, the planner's statistics, indexing beyond btree, and the SQL constructs seniors reach for that mid-level devs rewrite in Ruby. The last four cover live operations: vacuum and bloat, transaction isolation, zero-downtime migrations, and read replicas.
Read the first two in order. The rest stand alone and can be taken in any order. If your app has a single database and a single server, focus on lessons 1 to 6. If you are running multiple environments, replicas, or larger volumes, lessons 7 and 8 are where seniors spend their time during incidents.
Lesson 1
Walkthrough
EXPLAIN ANALYZE for Rails developers
Reading query plans beyond "is it using the index?" Cost vs actual time, rows estimated vs actual, the grammar of plan nodes, and the one number seniors check first.
Lesson 2
Walkthrough
The planner and its statistics
Why a query goes from 5ms to 800ms after a release without the SQL changing. Stats freshness, ANALYZE, pg_stat_user_tables, and the slow-query log. Where to look first.
Lesson 3
Walkthrough
Indexing beyond btree
Partial indexes, expression indexes, GIN/GIST for JSONB and full-text, BRIN for time-series, covering indexes with INCLUDE. When each is the right tool and when an extra index hurts.
Lesson 4
Walkthrough
Window functions and CTEs without the foot-gun
Running totals, top-N per group, gap detection, deduplication. Replacing 50 lines of Ruby with 4 lines of SQL. CTE materialization changes in PG12+ and when they bite.
Lesson 5
Walkthrough
MVCC, vacuum, and bloat
What UPDATE actually does. Why a 10GB table can hold 200MB of live data. When autovacuum is enough, when to intervene, and the VACUUM FULL vs pg_repack call.
Lesson 6
Walkthrough
Transaction isolation and locking
Read committed's lost-update problem, when SELECT FOR UPDATE is correct, advisory locks, reading pg_locks during an incident, and Rails's with_lock semantics.
Lesson 7
Walkthrough
Zero-downtime migrations
Add column with default in two steps. Add index concurrently. Rename column via shadow column. The patterns strong_migrations enforces and the table-size reflex.
Lesson 8
Walkthrough
Read replicas and multi-DB in Rails
When replicas help, when they do not, what replication lag breaks, Rails 6+ multi-database role API. Includes the "we added a replica and the app got slower" failure mode.