La respuesta corta es que el almacenamiento de la base de datos está más optimizado para la velocidad que para el espacio.
Por ejemplo, si insertó 100 filas en una tabla y luego eliminó todas las filas con una ID de número impar, el DBMS podría escribir una nueva tabla con solo 50 filas, pero es más eficiente que simplemente marque las filas eliminadas como espacio libre. y reutilícelos la próxima vez que inserte una fila. Por lo tanto, la mesa ocupa el doble de espacio que se necesita actualmente.
El uso de Postgres de "MVCC", en lugar de bloqueo, para la gestión de transacciones hace que esto sea aún más probable, ya que una ACTUALIZACIÓN generalmente implica escribir una nueva fila en el almacenamiento y luego marcar la fila anterior como eliminada una vez que ninguna transacción la esté mirando.
Al volcar y restaurar la base de datos, está recreando una base de datos sin todo este espacio libre. Esto es esencialmente lo que VACUUM FULL
El comando lo hace:reescribe los datos actuales en un archivo nuevo y luego elimina el archivo antiguo.
Hay una extensión distribuida con Postgres llamada pg_freespace
que le permite examinar algo de esto. p.ej. puede enumerar el tamaño de la tabla principal (sin incluir índices y columnas almacenados en tablas "TOAST" separadas) y el espacio libre utilizado por cada tabla con lo siguiente:
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;