@@ -17,69 +17,69 @@ defmodule EctoPSQLExtras.Bloat do
1717 end
1818
1919 def query ( _args \\ [ ] ) do
20- """
21- /* ECTO_PSQL_EXTRAS: Table and index bloat in your database ordered by most wasteful */
20+ { """
21+ /* ECTO_PSQL_EXTRAS: Table and index bloat in your database ordered by most wasteful */
2222
23- WITH constants AS (
24- SELECT current_setting('block_size')::numeric AS bs, 23 AS hdr, 4 AS ma
25- ), bloat_info AS (
26- SELECT
27- ma,bs,schemaname,tablename,
28- (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
29- (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
30- FROM (
31- SELECT
32- schemaname, tablename, hdr, ma, bs,
33- SUM((1-null_frac)*avg_width) AS datawidth,
34- MAX(null_frac) AS maxfracsum,
35- hdr+(
36- SELECT 1+count(*)/8
37- FROM pg_stats s2
38- WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
39- ) AS nullhdr
40- FROM pg_stats s, constants
41- GROUP BY 1,2,3,4,5
42- ) AS foo
43- ), table_bloat AS (
44- SELECT
45- schemaname, tablename, cc.relpages, bs,
46- CEIL((cc.reltuples*((datahdr+ma-
47- (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta
48- FROM bloat_info
49- JOIN pg_class cc ON cc.relname = bloat_info.tablename
50- JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
51- ), index_bloat AS (
52- SELECT
53- schemaname, tablename, bs,
54- COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
55- COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
56- FROM bloat_info
57- JOIN pg_class cc ON cc.relname = bloat_info.tablename
58- JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
59- JOIN pg_index i ON indrelid = cc.oid
60- JOIN pg_class c2 ON c2.oid = i.indexrelid
61- )
62- SELECT
63- type, schemaname, object_name, bloat, waste
64- FROM
65- (SELECT
66- 'table' as type,
67- schemaname,
68- tablename as object_name,
69- ROUND(CASE WHEN otta=0 THEN 0.0 ELSE table_bloat.relpages/otta::numeric END,1) AS bloat,
70- CASE WHEN relpages < otta THEN 0 ELSE (bs*(table_bloat.relpages-otta)::bigint)::bigint END AS waste
71- FROM
72- table_bloat
73- UNION
74- SELECT
75- 'index' as type,
76- schemaname,
77- tablename || '::' || iname as object_name,
78- ROUND(CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages/iotta::numeric END,1) AS bloat,
79- CASE WHEN ipages < iotta THEN 0 ELSE (bs*(ipages-iotta))::bigint END AS waste
80- FROM
81- index_bloat) bloat_summary
82- ORDER BY waste DESC, bloat DESC;
83- """
23+ WITH constants AS (
24+ SELECT current_setting('block_size')::numeric AS bs, 23 AS hdr, 4 AS ma
25+ ), bloat_info AS (
26+ SELECT
27+ ma,bs,schemaname,tablename,
28+ (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
29+ (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
30+ FROM (
31+ SELECT
32+ schemaname, tablename, hdr, ma, bs,
33+ SUM((1-null_frac)*avg_width) AS datawidth,
34+ MAX(null_frac) AS maxfracsum,
35+ hdr+(
36+ SELECT 1+count(*)/8
37+ FROM pg_stats s2
38+ WHERE null_frac<>0 AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename
39+ ) AS nullhdr
40+ FROM pg_stats s, constants
41+ GROUP BY 1,2,3,4,5
42+ ) AS foo
43+ ), table_bloat AS (
44+ SELECT
45+ schemaname, tablename, cc.relpages, bs,
46+ CEIL((cc.reltuples*((datahdr+ma-
47+ (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)) AS otta
48+ FROM bloat_info
49+ JOIN pg_class cc ON cc.relname = bloat_info.tablename
50+ JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
51+ ), index_bloat AS (
52+ SELECT
53+ schemaname, tablename, bs,
54+ COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
55+ COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
56+ FROM bloat_info
57+ JOIN pg_class cc ON cc.relname = bloat_info.tablename
58+ JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = bloat_info.schemaname AND nn.nspname <> 'information_schema'
59+ JOIN pg_index i ON indrelid = cc.oid
60+ JOIN pg_class c2 ON c2.oid = i.indexrelid
61+ )
62+ SELECT
63+ type, schemaname, object_name, bloat, waste
64+ FROM
65+ (SELECT
66+ 'table' as type,
67+ schemaname,
68+ tablename as object_name,
69+ ROUND(CASE WHEN otta=0 THEN 0.0 ELSE table_bloat.relpages/otta::numeric END,1) AS bloat,
70+ CASE WHEN relpages < otta THEN 0 ELSE (bs*(table_bloat.relpages-otta)::bigint)::bigint END AS waste
71+ FROM
72+ table_bloat
73+ UNION
74+ SELECT
75+ 'index' as type,
76+ schemaname,
77+ tablename || '::' || iname as object_name,
78+ ROUND(CASE WHEN iotta=0 OR ipages=0 THEN 0.0 ELSE ipages/iotta::numeric END,1) AS bloat,
79+ CASE WHEN ipages < iotta THEN 0 ELSE (bs*(ipages-iotta))::bigint END AS waste
80+ FROM
81+ index_bloat) bloat_summary
82+ ORDER BY waste DESC, bloat DESC;
83+ """ , [ ] }
8484 end
8585end
0 commit comments