PostgreSQL på en VPS: dimensionera minne och disk

En snabb PostgreSQL-databas är en databas där de data som läses ofta ryms i minnet. All dimensionering utgår därifrån: databasens storlek, den del som verkligen används, antalet anslutningar, och sedan disken och dess marginal. Den här guiden ger metoden, startinställningar för 4, 8 och 16 GB minne, och de frågor som mäter en befintlig databas.

Publicerad den 29 oktober 2026 Av Lästid: 10 minuter

Alla guider

I korthet

  1. Mät storleken på databasen och dess index, och sedan den del som läses ofta: det är den som måste rymmas i minnet.
  2. Utgångspunkt: shared_buffers på 25 % av minnet, effective_cache_size på 75 %, random_page_cost = 1.1 på NVMe-SSD.
  3. Varje anslutning är en process: bortom några tiotal aktiva anslutningar sätter du PgBouncer framför databasen.
  4. Disk: data och index om ett år, plus minst 30 % marginal. En full disk stoppar PostgreSQL.
  5. Andelen läsningar från cachen ska ligga över 99 %: under den nivån har databasen för lite minne.
  6. Säkerhetskopiera varje dag med pg_dump, utanför servern, och återställ regelbundet för att kontrollera resultatet.

Utgå från den aktiva datamängden

Minnet i en databasserver fungerar först och främst som cache: en sida som läses från minnet levereras mycket snabbare än en sida som läses från disk, även NVMe. Frågan är alltså inte bara ”hur stor är databasen?”, utan ”hur stor del läses ofta?”. En databas på 50 GB där bara de senaste tolv månaderna efterfrågas arbetar kanske med 8 GB.

På en befintlig databas ger två frågor den totala storleken och de största tabellerna, index inräknade:

SQL (psql)
SELECT pg_size_pretty(pg_database_size(current_database()));

SELECT relname AS namn,
       pg_size_pretty(pg_total_relation_size(relid)) AS storlek_med_index
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;

För en databas som ännu inte finns uppskattar du tabell för tabell: antalet rader som väntas om ett år × en rads genomsnittliga storlek, och lägger sedan till indexen, som ofta väger 30 till 100 % av datan. Exempel: 2 miljoner rader per månad, på 500 byte vardera, blir 12 GB data om ett år, och 18 till 24 GB med indexen.

Minnet: startinställningarna

PostgreSQL håller lästa sidor på två nivåer: sin egen cache (shared_buffers) och systemets filcache. Dokumentationen rekommenderar att utgå från 25 % av minnet för shared_buffers på en dedikerad server, och konstaterar att vinsten sällan blir större över 40 %: resten kommer systemets cache och sorteringarna till godo.

Parameter4 GB8 GB16 GBRoll
shared_buffers1 GB2 GB4 GBPostgreSQL:s egen cache
effective_cache_size3 GB6 GB12 GBDen uppskattade totala cachen, som styr valet av frågeplaner
work_mem8 MB16 MB32 MBMinnet för varje sortering eller hashning, per anslutning: multiplicera med antalet samtidiga frågor
maintenance_work_mem256 MB512 MB1 GBSkapande av index och VACUUM
random_page_cost1.11.11.1Den uppskattade kostnaden för en slumpmässig läsning: 4 som standard, långt över den verkliga kostnaden på NVMe-SSD

Värdena förutsätter att databasen är ensam på servern. Om applikationen körs bredvid drar du först av dess minne (processer, cache, kompilering) och tillämpar procentsatserna på resten: en server på 8 GB som kör en applikation på 3 GB ställs in som en databas på 5 GB.

postgresql.conf, för en server på 8 GB som bara kör databasen
shared_buffers = 2GB
effective_cache_size = 6GB
work_mem = 16MB
maintenance_work_mem = 512MB
random_page_cost = 1.1

shared_buffers träder i kraft först när PostgreSQL startas om; de andra parametrarna laddas om utan avbrott, med SELECT pg_reload_conf();.

För att veta om minnet räcker läser du andelen läsningar från cachen. För en affärsapplikation eller en webbplats ligger den över 99 %:

SQL (psql)
SELECT round(100.0 * blks_hit / nullif(blks_hit + blks_read, 0), 2) AS cacheandel
FROM pg_stat_database
WHERE datname = current_database();

Anslutningarna: en process var

PostgreSQL öppnar en process per anslutning och accepterar 100 som standard (max_connections). Varje process tar några megabyte i vila, mer när den sorterar eller hashar data (work_mem, ibland flera gånger i samma fråga). Att höja max_connections till 500 för att hänga med en pratsam applikation utsätter servern för minnesbrist vid första topp.

Det rätta svaret är en anslutningspoolare: PgBouncer, i läget transaction, låter hundratals anslutningar från applikationen dela på några tiotal verkliga anslutningar. Ramverken har också sin egen pool (SQLAlchemy, Prisma, HikariCP): ställ in dess storlek efter antalet vCPU på databasservern snarare än efter antalet användare.

Disken: volym, marginal och transaktionslogg

Disken i en PostgreSQL-server rymmer mer än tabellerna:

Regeln: volymen om ett år, plus minst 30 % marginal. Det är ingen lyx: när disken som rymmer transaktionsloggen blir full stänger PostgreSQL av sig själv för att skydda sina data. Följ beläggningen och utöka före 80 %.

När det gäller prestanda väntar varje bekräftad transaktion på att loggen skrivs till disk: lagringens latens bestämmer skrivhastigheten. Det är där en NVMe-SSD gör skillnad, mycket mer än vid läsningar, som minnet redan hanterar.

Processorn: en fråga, en kärna

En PostgreSQL-fråga körs på en enda kärna, utom de stora läsningar som motorn parallelliserar. Antalet vCPU bestämmer alltså hur många tunga frågor som hanteras samtidigt: 2 vCPU räcker för en affärsapplikation vid lanseringen, 4 till 8 passar databaser med hög belastning och tunga rapporter.

Innan du lägger till vCPU letar du upp de frågor som förbrukar dem. Tillägget pg_stat_statements sorterar dem efter total tid:

postgresql.conf, och sedan omstart
shared_preload_libraries = 'pg_stat_statements'
SQL (psql)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

SELECT calls, round(total_exec_time) AS ms_totalt,
       round(mean_exec_time::numeric, 1) AS ms_snitt, query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

Samma server som applikationen, eller en separat server?

Vid lanseringen är databasen på samma server som applikationen rätt val: ingen nätverkslatens mellan dem, anslutning via Unix-socket, en enda server att säkerhetskopiera och övervaka. Man delar upp dem när de konkurrerar om resurserna: en kompilering eller en trafiktopp som tömmer databasens cache, en databas som behöver hela minnet för sina data, eller olika krav på säkerhetskopiering.

Säkerhet och säkerhetskopior

Terminal: komprimerad export, och sedan återställning i en testdatabas
pg_dump -Fc -d min_databas -f min_databas-$(date +%F).dump
createdb min_databas_test
pg_restore -d min_databas_test min_databas-2026-10-29.dump

En snabb PostgreSQL-databas, på rätt server

VPS Pro körs på Intel Xeon-processorer, ECC-minne som rättar fel i realtid och speglade NVMe-SSD, med varje datablock verifierat med kontrollsumma och en krypterad säkerhetskopia varje natt, utanför maskinen. Heltäckande support ingår: när din databas blir långsam analyserar vi de långsamma frågorna och indexen och talar sedan om vilka inställningar som ger din applikation dess hastighet tillbaka.

Upptäck VPS Pro

Vanliga frågor

Hur mycket RAM behöver PostgreSQL?

Tillräckligt för att de data som läses ofta ska rymmas i minnet. För en affärsapplikation vid lanseringen räcker 4 GB, databas och applikation inräknade. Därefter mäter du andelen läsningar från cachen: så länge den ligger över 99 % räcker minnet.

Vilket värde ska shared_buffers ha?

25 % av minnet på en server som bara kör databasen, som PostgreSQL:s dokumentation rekommenderar: 1 GB på 4 GB, 2 GB på 8 GB, 4 GB på 16 GB. Över 40 % blir vinsten sällsynt, eftersom systemets cache sköter resten.

Hur många PostgreSQL-anslutningar klarar en VPS?

PostgreSQL accepterar 100 som standard, och varje anslutning är en process som förbrukar minne. I stället för att höja taket sätter du en anslutningspoolare som PgBouncer framför databasen: några tiotal verkliga anslutningar betjänar då hundratals anslutningar från applikationen.

Ska databasen och applikationen ligga på separata servrar?

Inte vid lanseringen: på samma server svarar databasen utan nätverkslatens, och allt säkerhetskopieras i ett block. Man delar upp dem när den ena stör den andra, till exempel när en kompilering eller en trafiktopp tömmer databasens cache.

Kontakta oss