How to Perform Full VACUUM in PostgreSQL

Their are two types of vacuum in PostgreSQL – ordinary vacuum and vacuum full. In PostgreSQL dead tuple is created when you delete or update any records in a table. Normal vacuum simply reclaims space and makes it available for re-use. However, In most cases, extra space is not returned back to the operating system.

Whereas, Vacuum Full release the free space occupied by dead tuple or obsolete records to the disk. This method require extra disk space because it write new copy of the table and doesn’t release the old copy until the operation is completed. This should use only if dead tuple is huge or a significant amount of space needs to be reclaimed from within the table. Please note that it acquire lock on the table and will be released once the operation is completed. So it’s better to bring down the application or processes accessing the table and then execute it.

Full VACUUM query in PostgreSQL to remove dead tuple and release disk space.

Sometimes, you will observe database performance has improved drastically after full vacuum. You can use below query to check dead tuple and for full vacuum activity.

SELECT 'VACUUM(FULL, ANALYZE,VERBOSE)  ' || table_oid::regclass || ';' ,
  /*current_database(), schemaname, */table_oid::regclass, /*reltuples::bigint, relpages::bigint, otta,*/
 -- ROUND((CASE WHEN otta=0 THEN 0.0 ELSE sml.relpages::FLOAT/otta END)::NUMERIC,1) AS tbloat,
  CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::BIGINT END AS wastedbytes
 FROM (
  SELECT
    cc.reltuples, cc.relpages, bs, cc.oid as table_oid,
    CEIL((cc.reltuples*((datahdr+ma-
      (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::FLOAT)) AS otta
  FROM (
    SELECT
      ma,bs,starelid,
      (datawidth+(hdr+ma-(CASE WHEN hdr%ma=0 THEN ma ELSE hdr%ma END)))::NUMERIC AS datahdr,
      (maxfracsum*(nullhdr+ma-(CASE WHEN nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
    FROM (
      SELECT
        starelid, hdr, ma, bs,
        SUM((1-stanullfrac)*stawidth) AS datawidth,
        MAX(stanullfrac) AS maxfracsum,
        hdr+(
          SELECT 1+COUNT(*)/8
          FROM pg_statistic s2
          WHERE stanullfrac<>0 AND s2.starelid = s.starelid
        ) AS nullhdr
      FROM pg_statistic s, (
        SELECT
          (SELECT current_setting('block_size')::NUMERIC) AS bs,
          CASE WHEN SUBSTRING(v,12,3) IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
          CASE WHEN v ~ 'mingw32' THEN 8 ELSE 4 END AS ma
        FROM (SELECT version() AS v) AS foo
      ) AS constants
      GROUP BY 1,2,3,4
    ) AS foo
  ) AS rs
  JOIN pg_class cc ON cc.oid = rs.starelid
  JOIN pg_namespace ns ON cc.relnamespace = ns.oid AND ns.nspname <> 'information_schema'
  WHERE cc.relkind IN('r','m')
) AS sml
JOIN pg_stat_all_tables sat ON sml.table_oid = sat.relid
--WHERE sat.schemaname like '%_DAT' 
--WHERE (CASE WHEN otta=0 THEN 0.0 ELSE sml.relpages::FLOAT/otta END) > 1.1 and sat.schemaname like '%_ADM'
ORDER BY wastedbytes DESC;