Buffer Pool, Caches & Memory Optimization
Tune shared_buffers, work_mem, and I/O settings for maximum query performance.
๐ฏ What You'll Learn
- shared_buffers: the main data page cache
- work_mem: per-operation sort/hash memory
- maintenance_work_mem and effective_cache_size
- Monitoring cache hit ratios and disk spills
- Complete tuning checklist for production servers
๐ง shared_buffers โ The Data Cache
shared_buffers is PostgreSQL's main memory area for caching data pages. Think of it as a desk where the database keeps frequently-used documents โ the bigger the desk, the fewer trips to the filing cabinet (disk). The default 128MB is like having a sticky note instead of a desk.
๐ work_mem โ Sort & Hash Memory
work_mem controls how much memory each sort, hash join, or hash aggregate can use. Too low means sorting on disk (slow); too high means a few complex queries can exhaust all RAM.
โ ๏ธ Common Mistake โ Setting work_mem Too High Globally
work_mem is per-operation, not per-query. A query with 5 hash joins uses 5 ร work_mem. With 100 concurrent connections at 256MB each, that's 128GB potentially. Set it low globally and high per-session for analytics.
work_mem
Prevent disk spills for sorts and hash operations
-- work_mem: memory per sort/hash operation per query
-- Check current setting:
SHOW work_mem;
-- Default: 4MB
-- Each sort, hash join, or hash aggregate gets this much memory
-- If data exceeds work_mem โ spills to disk (SLOW)
-- EXPLAIN shows when this happens:
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders ORDER BY total DESC;
-- Sort Method: external merge Disk: 52480kB โ BAD (disk spill!)
-- Sort Method: quicksort Memory: 25kB โ GOOD (in memory)
-- Set per-session for heavy que
...๐ง Other Memory Settings
maintenance_work_mem speeds up VACUUM and CREATE INDEX. effective_cache_size tells the planner how much total cache exists. temp_buffers controls temporary table memory.
๐ก Pro Tip โ effective_cache_size Doesn't Allocate Memory
effective_cache_size is purely informational โ it tells the optimizer "there's approximately this much cache available" so it can make better index vs. seq scan decisions. Set it to 75% of total RAM.
Maintenance & Planner Memory
maintenance_work_mem, effective_cache_size, temp_buffers
-- maintenance_work_mem: memory for maintenance operations
-- Used by: VACUUM, CREATE INDEX, ALTER TABLE ADD FK
SHOW maintenance_work_mem;
-- Default: 64MB (too low!)
-- Recommended: 1GB-2GB (only one maintenance op at a time)
-- Set globally since maintenance ops are infrequent:
-- maintenance_work_mem = 1GB
-- Impact on CREATE INDEX:
SET maintenance_work_mem = '64MB';
CREATE INDEX idx_test1 ON big_table (column1);
-- Time: 45 seconds
SET maintenance_work_mem = '1GB';
CREATE INDEX idx_test2
...๐ Monitoring Memory & I/O
You can't optimize what you can't measure. Monitor cache hit ratios, disk spills, and I/O patterns to know where memory is insufficient.
Memory & I/O Monitoring
Cache hits, disk spills, and I/O statistics
-- Monitor memory usage and I/O patterns
-- 1. Check if you need more shared_buffers:
-- If cache hit ratio < 99%, consider increasing
SELECT
datname,
blks_hit,
blks_read,
ROUND(blks_hit::decimal / NULLIF(blks_hit + blks_read, 0) * 100, 2)
AS cache_hit_pct
FROM pg_stat_database
WHERE datname = current_database();
-- 2. Check if work_mem is causing disk spills:
-- Look for "external merge" or "external sort" in EXPLAIN output
-- Also check pg_stat_statements for high tem
...๐๏ธ Production Tuning Checklist
A complete set of recommended settings for a production PostgreSQL server, covering memory, WAL, planner, connections, and autovacuum.
Production Tuning Checklist
Complete postgresql.conf settings for a 32GB server
-- TUNING CHECKLIST for a 32GB RAM server
-- postgresql.conf recommended settings:
-- Memory:
-- shared_buffers = 8GB # 25% of RAM
-- effective_cache_size = 24GB # 75% of RAM
-- work_mem = 32MB # conservative global
-- maintenance_work_mem = 2GB # for VACUUM, CREATE INDEX
-- WAL:
-- wal_buffers = 64MB # 1/32 of shared_buffers
-- checkpoint_completion_target = 0.9 # spread checkpoint I/O
-- max_wal_size = 4GB # before forced checkp
...๐ Quick Reference
| Setting | Rule of Thumb | Scope |
|---|---|---|
| shared_buffers | 25% of RAM | Global |
| effective_cache_size | 75% of RAM | Planner hint |
| work_mem | 16โ64MB global | Per-operation |
| maintenance_work_mem | 1โ2GB | Per-operation |
| random_page_cost | 1.1 (SSD) | Planner hint |
๐ Lesson Complete!
You now know how to tune PostgreSQL's memory for peak performance. Next, learn about massive data handling with bulk inserts and ETL!
Sign up for free to track which lessons you've completed and get learning reminders.