Det korta svaret är att databaslagring är mer optimerad för hastighet än utrymme.
Om du till exempel infogade 100 rader i en tabell och sedan tog bort varje rad med ett udda ID, skulle DBMS kunna skriva ut en ny tabell med endast 50 rader, men det är mer effektivt för den att helt enkelt markera de raderade raderna som ledigt utrymme och återanvänd dem nästa gång du infogar en rad. Därför tar bordet dubbelt så mycket plats som det behövs för närvarande.
Postgress användning av "MVCC", snarare än låsning, för transaktionshantering gör detta ännu mer sannolikt, eftersom en UPPDATERING vanligtvis innebär att man skriver en ny rad till lagringsutrymmet och sedan markerar den gamla raden som raderad när inga transaktioner tittar på den.
Genom att dumpa och återställa databasen återskapar du en DB utan allt detta lediga utrymme. Detta är i huvudsak vad VACUUM FULL
kommandot gör det - det skriver om nuvarande data till en ny fil och tar sedan bort den gamla filen.
Det finns en tillägg distribuerad med Postgres som heter pg_freespace
som låter dig undersöka en del av detta. t.ex. du kan lista huvudtabellens storlek (inte inklusive index och kolumner lagrade i separata "TOAST"-tabeller) och ledigt utrymme som används av varje tabell med följande:
Select oid::regclass::varchar as table,
pg_size_pretty(pg_relation_size(oid)/1024 * 1024) As size,
pg_size_pretty(sum(free)) As free
From (
Select c.oid,
(pg_freespace(c.oid)).avail As free
From pg_class c
Join pg_namespace n on n.oid = c.relnamespace
Where c.relkind = 'r'
And n.nspname Not In ('information_schema', 'pg_catalog')
) tbl
Group By oid
Order By pg_relation_size(oid) Desc, sum(free) Desc;