Skip to content

Instantly share code, notes, and snippets.

@CHERTS
Created March 6, 2025 09:41
Show Gist options
  • Save CHERTS/757f12ed82c2ed928f7a6c46c85510da to your computer and use it in GitHub Desktop.
Save CHERTS/757f12ed82c2ed928f7a6c46c85510da to your computer and use it in GitHub Desktop.
PostgreSQL autovacuum forecast
WITH rel_set AS (
SELECT
oid
, CASE split_part(
split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2)
, ','
, 1
)
WHEN '' THEN NULL
ELSE
split_part(
split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2)
, ','
, 1
)::bigint
END rel_av_vac_threshold
, CASE split_part(
split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2)
, ','
, 1
)
WHEN '' THEN NULL
ELSE
split_part(
split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2)
, ','
, 1
)::numeric
END rel_av_vac_scale_factor
FROM
pg_class
)
SELECT
psut.schemaname "schema"
, psut.relname table_name
, to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') last_vacuum
, to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') last_autovacuum
, to_char(c.reltuples, '9G999G999G999') n_tup
, to_char(psut.n_dead_tup, '9G999G999G999') dead_tup
, to_char(
coalesce(rs.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::bigint) + coalesce(
rs.rel_av_vac_scale_factor
, current_setting('autovacuum_vacuum_scale_factor')::numeric
) * c.reltuples
, '9G999G999G999'
) av_threshold
, CASE
WHEN coalesce(rs.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::bigint) + coalesce(
rs.rel_av_vac_scale_factor
, current_setting('autovacuum_vacuum_scale_factor')::numeric
) * c.reltuples < psut.n_dead_tup
THEN '*'
ELSE ''
END expect_av
FROM
pg_stat_user_tables psut
JOIN
pg_class c
ON psut.relid = c.oid
JOIN
rel_set rs
ON psut.relid = rs.oid
ORDER BY
c.reltuples DESC;
-- show autovacuum forecast extended
-- nspname - the namespace of the table
-- relname - the table name
-- reltuples - total number of tuples
-- n_dead_tup - number of dead tuples needing to be vacuumed
-- v_threshold - autovacuum threshold for dead tuples
-- n_mod_since_analyze - number of tuples modified since last analyze
-- a_threshold - autoanalyze threshold for dead tuples
-- caf - custom autoanalyze factor
-- cat - custom autoanalyze threshold
-- cvt - custom autovacuum threshold
-- cvf - custom autoanalyze factor
-- gaf - global autoanalyze factor
-- gat - gloval autovacuum threshold
-- gvf - global autovacuum factor
-- gvt - global autovacuum threshold
WITH raw_data AS (
SELECT
pg_namespace.nspname
, pg_class.relname
, pg_class.oid relid
, pg_class.reltuples
, pg_stat_all_tables.n_dead_tup
, pg_stat_all_tables.n_mod_since_analyze
, (
SELECT
split_part(x, '=', 2)
FROM
unnest(pg_class.reloptions) q(x)
WHERE
x ~ '^autovacuum_analyze_scale_factor='
) c_analyze_factor
, (
SELECT
split_part(x, '=', 2)
FROM
unnest(pg_class.reloptions) q(x)
WHERE
x ~ '^autovacuum_analyze_threshold='
) c_analyze_threshold
, (
SELECT
split_part(x, '=', 2)
FROM
unnest(pg_class.reloptions) q(x)
WHERE
x ~ '^autovacuum_vacuum_scale_factor='
) c_vacuum_factor
, (
SELECT
split_part(x, '=', 2)
FROM
unnest(pg_class.reloptions) q(x)
WHERE
x ~ '^autovacuum_vacuum_threshold='
) c_vacuum_threshold
, to_char(pg_stat_all_tables.last_vacuum, 'YYYY-MM-DD HH24:MI:SS') last_vacuum
, to_char(pg_stat_all_tables.last_autovacuum, 'YYYY-MM-DD HH24:MI:SS') last_autovacuum
FROM
pg_class
JOIN
pg_namespace
ON pg_class.relnamespace = pg_namespace.oid
LEFT JOIN
pg_stat_all_tables
ON pg_class.oid = pg_stat_all_tables.relid
WHERE
n_dead_tup IS NOT NULL AND
nspname NOT IN ('information_schema', 'pg_catalog') AND
nspname NOT LIKE 'pg_toast%' AND
pg_class.relkind = 'r'
)
, data AS (
SELECT
*
, coalesce(raw_data.c_analyze_factor, current_setting('autovacuum_analyze_scale_factor'))::double precision analyze_factor
, coalesce(raw_data.c_analyze_threshold, current_setting('autovacuum_analyze_threshold'))::double precision analyze_threshold
, coalesce(raw_data.c_vacuum_factor, current_setting('autovacuum_vacuum_scale_factor'))::double precision vacuum_factor
, coalesce(raw_data.c_vacuum_threshold, current_setting('autovacuum_vacuum_threshold'))::double precision vacuum_threshold
FROM
raw_data
)
SELECT
relid
, nspname
, relname
, reltuples
, n_dead_tup
, round(reltuples * vacuum_factor + vacuum_threshold) v_threshold
, n_mod_since_analyze
, round(reltuples * analyze_factor + analyze_threshold) a_threshold
, c_analyze_factor caf
, c_analyze_threshold cat
, c_vacuum_factor cvf
, c_vacuum_threshold cvt
, analyze_factor gaf
, analyze_threshold gat
, vacuum_factor gvf
, vacuum_threshold gvt
, last_vacuum
, last_autovacuum
FROM
data
ORDER BY
n_dead_tup DESC;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment