Glossary: Storage
shared_buffers is an array, not a budget
Also called: buffer pool, shared buffer cache.
Definition, revised in place. Last updated .
shared_buffers is a single block of shared memory, reserved in full when the server starts and divided into slots the size of a page. Each slot holds one page of one relation, and every backend reads and writes through the same set of slots. It caches table and index pages and nothing else. Sorts, hashes, vacuum’s dead-row list and the catalog caches each backend keeps are separate allocations, and none of them comes out of this one.
What the setting is not
It is not a ceiling the server grows into. The memory is taken at startup whether the database is one megabyte or one terabyte, and changing the value requires a restart, which is the practical reason it tends to be set once and never revisited.
It is not the only cache in play either. Below it sits the operating system’s own page cache, holding many of the same pages, and a read that misses the pool very often does not reach the disk at all. That is why a modest pool on a large machine performs better than the arithmetic suggests, and why the hit ratio computed from the server’s counters answers a narrower question than people think.
And it is not a per-connection figure. The widely repeated advice to set it to a quarter of memory is a starting point with no mechanism behind it; the mechanism is that a larger pool holds more pages and also gives each checkpoint more dirty pages to write, so past a point the gains and the write stalls arrive together.
Counting the slots
The extension that exposes the pool reports one row per slot, so the number of rows is the size of the array.
CREATE EXTENSION pg_buffercache;
SELECT current_setting('shared_buffers') AS shared_buffers,
current_setting('block_size') AS block_size,
count(*) AS buffers,
count(*) FILTER (WHERE relfilenode IS NOT NULL) AS holding_a_page
FROM pg_buffercache;
CREATE EXTENSION
shared_buffers | block_size | buffers | holding_a_page
----------------+------------+---------+----------------
128MB | 8192 | 16384 | 7034
(1 row)
The first two columns multiply out to the third, which is the whole structure: a fixed count of fixed-size slots. The last column is how many currently hold anything, and on a server that has just started most of the array is empty. A pool that never fills is a pool larger than the working set, which is a more useful thing to know than any ratio.
Deciding whether to change it
Measure what the pool is holding before resizing it. Grouping the same view by relation shows which tables and indexes actually occupy the array, and a pool dominated by one table nobody queries is a different problem from a pool that is genuinely too small. Two neighbouring ideas matter more than the number itself: double buffering explains the layer underneath, and cache hit ratio explains why the obvious metric is close to useless as a target.
What the setting leaves for everything else is the other half of the decision, and the memory budget calculator adds up the worst case around it: the per-backend exposure at your work_mem, every autovacuum worker at once, and what remains for the operating system’s own cache.