keepcalculator

06 Numbers and Powers

PostgreSQL Performance Tuning: Key Parameters

Card No. 06·54701 · Updated · Standard formula, shown below

shared_buffers (MB) 4,096 MB
work_mem (MB)
41 MB
Result
effective_cache_size (MB)
12,288 MB
Result
Total RAM (GB)
16 GB
You entered
You enter
Total RAM (GB), max_connections
You get
shared_buffers (MB), work_mem (MB), effective_cache_size (MB)
Rounding
0 dp

To improve PostgreSQL performance, you set a handful of configuration parameters in postgresql.conf—most importantly shared_buffers, work_mem, effective_cache_size, and max_connections. These control memory usage, disk I/O, and query execution, and tuning them correctly can dramatically reduce query times and increase throughput.

Formula

The calculator above gives starting values for three core PostgreSQL memory parameters based on your system’s total RAM and expected maximum connections. The formulas used are common starting points recommended by PostgreSQL experts:

  • shared_buffers = 25% of total RAM, capped at 8 GB (since PostgreSQL on most platforms cannot efficiently use more than that for this buffer).
  • effective_cache_size = 75% of total RAM, which tells the query planner how much memory the operating system is likely to use for file caching.
  • work_mem = (total RAM – shared_buffers) / (max_connections * 3). This is a rough per-operation memory budget; the factor of 3 accounts for multiple sort/hash operations per connection.

Variables: t = total system RAM in GB, c = max_connections, sb = shared_buffers in MB, wm = work_mem in MB, ec = effective_cache_size in MB.

Worked Example

Suppose your server has 16 GB of RAM and you expect 100 maximum connections. Using the defaults from the calculator:

  1. shared_buffers = min(16 × 1024 × 0.25, 8192) = min(4096, 8192) = 4096 MB (4 GB).
  2. effective_cache_size = 16 × 1024 × 0.75 = 12288 MB (12 GB).
  3. work_mem = max(4, round((16 × 1024 – 4096) / (100 × 3))) = max(4, round(12288 / 300)) = max(4, 41) = 41 MB.

So you would set shared_buffers = 4096MB, effective_cache_size = 12288MB, and work_mem = 41MB in your configuration. These are starting points; you should monitor performance and adjust based on actual workload.

Background: Why PostgreSQL Tuning Matters

PostgreSQL comes with conservative defaults that work on small machines but often underperform on production servers. The default shared_buffers is 128 MB, work_mem is 4 MB, and effective_cache_size is 524288 (512 MB). On a server with 64 GB of RAM, these defaults force PostgreSQL to constantly read from disk and spill sorts to disk, causing slow queries and high I/O.

Tuning these parameters aligns PostgreSQL’s memory usage with your hardware, reducing disk reads and allowing more operations to happen in memory. This is especially important for read-heavy workloads, complex joins, and large sorts.

How to Choose the Right Values

There is no one-size-fits-all setting; the optimal values depend on your workload, available RAM, and number of concurrent connections. Here are general guidelines:

  • shared_buffers: Start at 25% of total RAM, but never exceed 8 GB on most systems. If you have a dedicated database server with 32 GB RAM, 8 GB is a good starting point. For 64 GB RAM, still consider 8 GB unless you have tested higher values.
  • effective_cache_size: Set to about 75% of total RAM. This is a planner hint, not actual memory allocation, so it can be higher than shared_buffers.
  • work_mem: This is per sort or hash operation, not per connection. Setting it too high can cause out-of-memory errors when many queries run concurrently. Start with the formula above, then monitor for disk sorts and increase gradually if needed.
  • max_connections: Each connection consumes memory, so don’t set it higher than needed. If you use connection pooling (like PgBouncer), you can keep it low.

Always test changes in a staging environment and use tools like EXPLAIN ANALYZE to see the impact on slow queries.

Common Problems and Misconceptions

A frequent mistake is setting shared_buffers too high. PostgreSQL also uses the operating system cache, and double-caching can waste memory. Another misconception is that work_mem is a total memory limit per query; it’s actually per operation, so a query with multiple sorts can use many times that value.

Also, changing parameters requires a restart for some (like shared_buffers) while others (like work_mem) can be changed on the fly with SET or ALTER SYSTEM and reloaded. Always check the documentation for which parameters require a restart.

Finally, don’t ignore effective_cache_size. If it’s too low, the planner may choose index scans when sequential scans would be faster, and vice versa.

Comparing with Other Database Tuning

Unlike MySQL, PostgreSQL’s memory model is more modular. In MySQL, the InnoDB buffer pool is the main memory area. In PostgreSQL, you have shared_buffers for cached data, work_mem for per-operation memory, and maintenance_work_mem for VACUUM and index creation. This separation allows finer control but requires more careful tuning.

Also, PostgreSQL uses a cost-based query planner that relies on effective_cache_size to estimate I/O costs, which is not a concept in some other databases.

Costs and Risks of Incorrect Tuning

Setting work_mem too high can lead to out-of-memory errors and even crash the server if many queries run concurrently. Setting shared_buffers too low can cause excessive disk I/O, while too high can waste memory and slow down the system due to inefficient caching.

There is no financial cost to tuning, but there is a risk of downtime if you misconfigure and need to restart. Always back up your configuration file before making changes, and test on a non-production instance first.

Safety and Best Practices

When editing postgresql.conf, make a backup and use pg_ctl reload to apply changes that don’t require a restart. For parameters that require a restart, schedule a maintenance window.

Monitor performance using pg_stat_statements and system tools like top or iostat. Look for high disk reads, low cache hit ratios, and slow queries. Adjust one parameter at a time and measure the effect.

Also, keep in mind that these are starting points. Real-world tuning requires iterative testing and monitoring.

Frequently Asked Questions

What is the most important PostgreSQL performance parameter?

Most experts agree that shared_buffers is the most critical, as it controls the main cache for database pages. However, work_mem and effective_cache_size are equally important for query performance. A balanced approach is best.

Can I change these parameters without restarting?

Some parameters, like work_mem and effective_cache_size, can be changed with ALTER SYSTEM and reloaded with pg_ctl reload without restarting. shared_buffers requires a restart because it allocates shared memory at startup.

How do I know if my work_mem is too low?

If you see

Related

Formula used
in t | Total RAM (GB) | GB | 16 | 1 | 1024
in c | max_connections | - | 100 | 10 | 1000
out sb | shared_buffers (MB) | MB | min(t * 1024 * 0.25, 8192) | 0
out wm | work_mem (MB) | MB | max(4, round((t * 1024 - sb) / (c * 3))) | 0
out ec | effective_cache_size (MB) | MB | round(t * 1024 * 0.75) | 0

Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →