Last active
October 29, 2024 15:40
-
-
Save seejee/26f979ee169a1a430ca2 to your computer and use it in GitHub Desktop.
Postgres Maintenance Scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELECT nspname || '.' || relname AS "relation", | |
pg_size_pretty(pg_relation_size(C.oid)) AS "size" | |
FROM pg_class C | |
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) | |
WHERE nspname NOT IN ('pg_catalog', 'information_schema') | |
ORDER BY pg_relation_size(C.oid) DESC | |
LIMIT 20; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELECT nspname || '.' || relname AS "relation", | |
pg_size_pretty(pg_total_relation_size(C.oid)) AS "total_size" | |
FROM pg_class C | |
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) | |
WHERE nspname NOT IN ('pg_catalog', 'information_schema') | |
AND C.relkind <> 'i' | |
AND nspname !~ '^pg_toast' | |
ORDER BY pg_total_relation_size(C.oid) DESC | |
LIMIT 20; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELECT | |
current_database(), schemaname, tablename, /*reltuples::bigint, relpages::bigint, otta,*/ | |
ROUND(CASE WHEN otta=0 THEN 0.0 ELSE sml.relpages/otta::NUMERIC END,1) AS tbloat, | |
pg_size_pretty(CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::BIGINT END) AS wastedbytes, | |
iname, /*ituples::bigint, ipages::bigint, iotta,*/ | |
ROUND(CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages/iotta::NUMERIC END,1) AS ibloat, | |
CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes | |
FROM ( | |
SELECT | |
schemaname, tablename, cc.reltuples, cc.relpages, bs, | |
CEIL((cc.reltuples*((datahdr+ma- | |
(CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::FLOAT)) AS otta, | |
COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages, | |
COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::FLOAT)),0) AS iotta -- very rough approximation, assumes all cols | |
FROM ( | |
SELECT | |
ma,bs,schemaname,tablename, | |
(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 | |
schemaname, tablename, hdr, ma, bs, | |
SUM((1-null_frac)*avg_width) AS datawidth, | |
MAX(null_frac) AS maxfracsum, | |
hdr+( | |
SELECT 1+COUNT(*)/8 | |
FROM pg_stats s2 | |
WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename | |
) AS nullhdr | |
FROM pg_stats 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,5 | |
) AS foo | |
) AS rs | |
JOIN pg_class cc ON cc.relname = rs.tablename | |
JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = rs.schemaname AND nn.nspname <> 'information_schema' | |
LEFT JOIN pg_index i ON indrelid = cc.oid | |
LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid | |
) AS sml | |
ORDER BY | |
CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::BIGINT END DESC |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
WITH table_scans as ( | |
SELECT relid, | |
tables.idx_scan + tables.seq_scan as all_scans, | |
( tables.n_tup_ins + tables.n_tup_upd + tables.n_tup_del ) as writes, | |
pg_relation_size(relid) as table_size | |
FROM pg_stat_user_tables as tables | |
), | |
all_writes as ( | |
SELECT sum(writes) as total_writes | |
FROM table_scans | |
), | |
indexes as ( | |
SELECT idx_stat.relid, idx_stat.indexrelid, | |
idx_stat.schemaname, idx_stat.relname as tablename, | |
idx_stat.indexrelname as indexname, | |
idx_stat.idx_scan, | |
pg_relation_size(idx_stat.indexrelid) as index_bytes, | |
indexdef ~* 'USING btree' AS idx_is_btree | |
FROM pg_stat_user_indexes as idx_stat | |
JOIN pg_index | |
USING (indexrelid) | |
JOIN pg_indexes as indexes | |
ON idx_stat.schemaname = indexes.schemaname | |
AND idx_stat.relname = indexes.tablename | |
AND idx_stat.indexrelname = indexes.indexname | |
WHERE pg_index.indisunique = FALSE | |
), | |
index_ratios AS ( | |
SELECT schemaname, tablename, indexname, | |
idx_scan, all_scans, | |
round(( CASE WHEN all_scans = 0 THEN 0.0::NUMERIC | |
ELSE idx_scan::NUMERIC/all_scans * 100 END),2) as index_scan_pct, | |
writes, | |
round((CASE WHEN writes = 0 THEN idx_scan::NUMERIC ELSE idx_scan::NUMERIC/writes END),2) | |
as scans_per_write, | |
pg_size_pretty(index_bytes) as index_size, | |
pg_size_pretty(table_size) as table_size, | |
idx_is_btree, index_bytes | |
FROM indexes | |
JOIN table_scans | |
USING (relid) | |
), | |
index_groups AS ( | |
SELECT 'Never Used Indexes' as reason, *, 1 as grp | |
FROM index_ratios | |
WHERE | |
idx_scan = 0 | |
and idx_is_btree | |
UNION ALL | |
SELECT 'Low Scans, High Writes' as reason, *, 2 as grp | |
FROM index_ratios | |
WHERE | |
scans_per_write <= 1 | |
and index_scan_pct < 10 | |
and idx_scan > 0 | |
and writes > 100 | |
and idx_is_btree | |
UNION ALL | |
SELECT 'Seldom Used Large Indexes' as reason, *, 3 as grp | |
FROM index_ratios | |
WHERE | |
index_scan_pct < 5 | |
and scans_per_write > 1 | |
and idx_scan > 0 | |
and idx_is_btree | |
and index_bytes > 100000000 | |
UNION ALL | |
SELECT 'High-Write Large Non-Btree' as reason, index_ratios.*, 4 as grp | |
FROM index_ratios, all_writes | |
WHERE | |
( writes::NUMERIC / ( total_writes + 1 ) ) > 0.02 | |
AND NOT idx_is_btree | |
AND index_bytes > 100000000 | |
ORDER BY grp, index_bytes DESC ) | |
SELECT reason, schemaname, tablename, indexname, | |
index_scan_pct, scans_per_write, index_size, table_size | |
FROM index_groups; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment