The question is old, but since both answers are wrong or misleading, I'll add another one.
When updating a row, Postgres writes a new row version and the old one is eventually removed by VACUUM
after no running transaction can see it any more.
Plain VACUUM
does not return disk space from the physical file that contains the table to the system, unless it finds completely dead or empty blocks at the physical end of the table. You need to run VACUUM FULL
or CLUSTER
to aggressively compact the table and return excess space to the system. This is not typically desirable in normal operation. Postgres can re-use dead tuples to keep new row versions on the same data page, which benefits performance.
In your case, since you update every row, the size of the table is doubled (from its minimum size). It's advisable to run VACUUM FULL
or CLUSTER
to return the bloat to the system.
Both take an exclusive lock on the table. If that interferes with concurrent access, consider pg_repack
, which can do the same without exclusive locks.
To clarify: Running CLUSTER
reclaims the space completely. No VACUUM FULL
is needed after CLUSTER
(and vice versa).
More details: