Skip to content

Commit eea4998

Browse files
committed
reworked b1; "extended" mode; better output for 2, b1
1 parent 12aefc5 commit eea4998

File tree

4 files changed

+144
-102
lines changed

4 files changed

+144
-102
lines changed

init/generate.sh

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
55
OUT="start.psql"
66

77
cd "$DIR/.."
8-
echo "\\echo '\\033[1;35mMenu:\\033[0m'" > "$OUT"
8+
echo "" > "$OUT"
9+
echo "select coalesce(current_setting('postgresdba.extended', true), 'off') = 'on' as postgresdba_extended \\gset" >> "$OUT"
10+
echo "\\echo '\\033[1;35mMenu:\\033[0m'" >> "$OUT"
911
for f in ./sql/*.sql
1012
do
1113
prefix=$(echo $f | sed -e 's/_.*$//g' -e 's/^.*\///g')
@@ -33,15 +35,15 @@ for f in ./sql/*.sql
3335
do
3436
prefix=$(echo $f | sed -e 's/_.*$//g' -e 's/^.*\///g')
3537
echo "\\elif :d_step_is_$prefix" >> "$OUT"
36-
echo " \\i $f" >> "$OUT"
38+
echo " \\ir $f" >> "$OUT"
3739
echo " \\prompt 'Press <Enter> to continue…' d_dummy" >> "$OUT"
38-
echo " \\i ./$OUT" >> "$OUT"
40+
echo " \\ir ./$OUT" >> "$OUT"
3941
done
4042
echo "\\else" >> "$OUT"
4143
echo " \\echo" >> "$OUT"
4244
echo " \\echo '\\033[1;31mError:\\033[0m Unknown option! Try again.'" >> "$OUT"
4345
echo " \\echo" >> "$OUT"
44-
echo " \\i ./$OUT" >> "$OUT"
46+
echo " \\ir ./$OUT" >> "$OUT"
4547
echo "\\endif" >> "$OUT"
4648

4749
echo "Done."

sql/2_table_sizes.sql

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,29 @@ with data as (
3030
select * from data
3131
)
3232
select
33-
coalesce(nullif(schema_name, 'public') || '.', '') || table_name as table,
33+
coalesce(nullif(schema_name, 'public') || '.', '') || table_name as "Table",
3434
'~' || case
3535
when row_estimate > 10^12 then round(row_estimate::numeric / 10^12::numeric, 0)::text || 'T'
3636
when row_estimate > 10^9 then round(row_estimate::numeric / 10^9::numeric, 0)::text || 'B'
3737
when row_estimate > 10^6 then round(row_estimate::numeric / 10^6::numeric, 0)::text || 'M'
3838
when row_estimate > 10^3 then round(row_estimate::numeric / 10^3::numeric, 0)::text || 'k'
3939
else row_estimate::text
40-
end as rows,
41-
pg_size_pretty(total_bytes) || ' (' || round(100 * total_bytes::numeric / sum(total_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "total (% of all)",
42-
pg_size_pretty(table_bytes) || ' (' || round(100 * table_bytes::numeric / sum(table_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "table (% of all tables)",
43-
pg_size_pretty(index_bytes) || ' (' || round(100 * index_bytes::numeric / sum(index_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "index (% of all indexes)",
44-
pg_size_pretty(toast_bytes) || ' (' || round(100 * toast_bytes::numeric / sum(toast_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "toast (% of all toast data)"
45-
/*,
40+
end as "Rows",
41+
pg_size_pretty(total_bytes) || ' (' || round(100 * total_bytes::numeric / sum(total_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "Total Size",
42+
pg_size_pretty(table_bytes) || ' (' || round(100 * table_bytes::numeric / sum(table_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "Table Size",
43+
pg_size_pretty(index_bytes) || ' (' || round(100 * index_bytes::numeric / sum(index_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "Index(es) Size",
44+
pg_size_pretty(toast_bytes) || ' (' || round(100 * toast_bytes::numeric / sum(toast_bytes) over (partition by (schema_name is null)), 2)::text || '%)' as "TOAST Size"
45+
\if :postgresdba_extended
46+
,
4647
row_estimate,
4748
total_bytes,
4849
table_bytes,
4950
index_bytes,
5051
toast_bytes,
5152
schema_name,
5253
table_name,
53-
oid*/
54+
oid
55+
\endif
5456
from data2
5557
where schema_name is distinct from 'information_schema'
5658
order by oid is null desc, total_bytes desc nulls last;

sql/b1_table_estimation.sql

Lines changed: 101 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,112 @@
11
--Tables Bloat, rough estimation
22

3-
--enhanced version of https://github.com/ioguix/pgsql-bloat-estimation/blob/master/table/table_bloat.sql
3+
--This SQL is derived from https://github.com/ioguix/pgsql-bloat-estimation/blob/master/table/table_bloat.sql
44

5-
/* WARNING: executed with a non-superuser role, the query inspect only tables you are granted to read.
5+
/*
6+
* WARNING: executed with a non-superuser role, the query inspect only tables you are granted to read.
67
* This query is compatible with PostgreSQL 9.0 and more
78
*/
89

9-
with data as (
10-
SELECT current_database(), schemaname, tblname, bs*tblpages AS real_size,
11-
(tblpages-est_tblpages)*bs AS extra_size,
12-
CASE WHEN tblpages - est_tblpages > 0
13-
THEN 100 * (tblpages - est_tblpages)/tblpages::float
14-
ELSE 0
15-
END AS extra_ratio, fillfactor, (tblpages-est_tblpages_ff)*bs AS bloat_size,
16-
CASE WHEN tblpages - est_tblpages_ff > 0
17-
THEN 100 * (tblpages - est_tblpages_ff)/tblpages::float
18-
ELSE 0
19-
END AS bloat_ratio, is_na
20-
-- , (pst).free_percent + (pst).dead_tuple_percent AS real_frag
21-
FROM (
22-
SELECT ceil( reltuples / ( (bs-page_hdr)/tpl_size ) ) + ceil( toasttuples / 4 ) AS est_tblpages,
23-
ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff,
24-
tblpages, fillfactor, bs, tblid, schemaname, tblname, heappages, toastpages, is_na
25-
-- , stattuple.pgstattuple(tblid) AS pst
26-
FROM (
27-
SELECT
28-
( 4 + tpl_hdr_size + tpl_data_size + (2*ma)
29-
- CASE WHEN tpl_hdr_size%ma = 0 THEN ma ELSE tpl_hdr_size%ma END
30-
- CASE WHEN ceil(tpl_data_size)::int%ma = 0 THEN ma ELSE ceil(tpl_data_size)::int%ma END
31-
) AS tpl_size, bs - page_hdr AS size_per_block, (heappages + toastpages) AS tblpages, heappages,
32-
toastpages, reltuples, toasttuples, bs, page_hdr, tblid, schemaname, tblname, fillfactor, is_na
33-
FROM (
34-
SELECT
35-
tbl.oid AS tblid, ns.nspname AS schemaname, tbl.relname AS tblname, tbl.reltuples,
36-
tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages,
37-
coalesce(toast.reltuples, 0) AS toasttuples,
38-
coalesce(substring(
39-
array_to_string(tbl.reloptions, ' ')
40-
FROM '%fillfactor=#"__#"%' FOR '#')::smallint, 100) AS fillfactor,
41-
current_setting('block_size')::numeric AS bs,
42-
CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma,
43-
24 AS page_hdr,
44-
23 + CASE WHEN MAX(coalesce(null_frac,0)) > 0 THEN ( 7 + count(*) ) / 8 ELSE 0::int END
45-
+ CASE WHEN tbl.relhasoids THEN 4 ELSE 0 END AS tpl_hdr_size,
46-
sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024) ) AS tpl_data_size,
47-
bool_or(att.atttypid = 'pg_catalog.name'::regtype) AS is_na
48-
FROM pg_attribute AS att
49-
JOIN pg_class AS tbl ON att.attrelid = tbl.oid
50-
JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace
51-
JOIN pg_stats AS s ON s.schemaname=ns.nspname
52-
AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname
53-
LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid
54-
WHERE att.attnum > 0 AND NOT att.attisdropped
55-
AND tbl.relkind = 'r'
56-
GROUP BY 1,2,3,4,5,6,7,8,9,10, tbl.relhasoids
57-
ORDER BY 2,3
58-
) AS s
59-
) AS s2
60-
) AS s3
10+
11+
with step1 as (
12+
select
13+
tbl.oid tblid,
14+
ns.nspname as schema_name,
15+
tbl.relname as table_name,
16+
tbl.reltuples,
17+
tbl.relpages as heappages,
18+
coalesce(toast.relpages, 0) as toastpages,
19+
coalesce(toast.reltuples, 0) as toasttuples,
20+
coalesce(substring(array_to_string(tbl.reloptions, ' ') from '%fillfactor=#"__#"%' for '#')::int2, 100) as fillfactor,
21+
current_setting('block_size')::numeric as bs,
22+
case when version() ~ 'mingw32|64-bit|x86_64|ppc64|ia64|amd64' then 8 else 4 end as ma, -- NS: TODO: check it
23+
24 as page_hdr,
24+
23 + case when max(coalesce(null_frac, 0)) > 0 then (7 + count(*)) / 8 else 0::int end
25+
+ case when tbl.relhasoids then 4 else 0 end as tpl_hdr_size,
26+
sum((1 - coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) as tpl_data_size,
27+
bool_or(att.atttypid = 'pg_catalog.name'::regtype) or count(att.attname) <> count(s.attname) as is_na
28+
from pg_attribute as att
29+
join pg_class as tbl on att.attrelid = tbl.oid and tbl.relkind = 'r'
30+
join pg_namespace as ns on ns.oid = tbl.relnamespace
31+
join pg_stats as s on s.schemaname = ns.nspname and s.tablename = tbl.relname and not s.inherited and s.attname = att.attname
32+
left join pg_class as toast on tbl.reltoastrelid = toast.oid
33+
where att.attnum > 0 and not att.attisdropped
34+
group by 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, tbl.relhasoids
35+
order by 2, 3
36+
), step2 as (
37+
select
38+
*,
39+
(
40+
4 + tpl_hdr_size + tpl_data_size + (2 * ma)
41+
- case when tpl_hdr_size % ma = 0 then ma else tpl_hdr_size % ma end
42+
- case when ceil(tpl_data_size)::int % ma = 0 then ma else ceil(tpl_data_size)::int % ma end
43+
) as tpl_size,
44+
bs - page_hdr as size_per_block,
45+
(heappages + toastpages) as tblpages
46+
from step1
47+
), step3 as (
48+
select
49+
*,
50+
ceil(reltuples / ((bs - page_hdr) / tpl_size)) + ceil(toasttuples / 4) as est_tblpages,
51+
ceil(reltuples / ((bs - page_hdr) * fillfactor / (tpl_size * 100))) + ceil(toasttuples / 4) as est_tblpages_ff
52+
-- , stattuple.pgstattuple(tblid) as pst
53+
from step2
54+
), step4 as (
55+
select
56+
*,
57+
tblpages * bs as real_size,
58+
(tblpages - est_tblpages) * bs as extra_size,
59+
case when tblpages - est_tblpages > 0 then 100 * (tblpages - est_tblpages) / tblpages::float else 0 end as extra_ratio,
60+
(tblpages - est_tblpages_ff) * bs as bloat_size,
61+
case when tblpages - est_tblpages_ff > 0 then 100 * (tblpages - est_tblpages_ff) / tblpages::float else 0 end as bloat_ratio
62+
-- , (pst).free_percent + (pst).dead_tuple_percent as real_frag
63+
from step3
6164
-- WHERE NOT is_na
6265
-- AND tblpages*((pst).free_percent + (pst).dead_tuple_percent)::float4/100 >= 1
6366
)
64-
select current_database, schemaname, tblname,
65-
real_size, pg_size_pretty(real_size::numeric) as real_size_pretty,
66-
extra_size, pg_size_pretty(extra_size::numeric) as extra_size_pretty,
67-
extra_ratio as "extra_ratio, %",
68-
bloat_size, pg_size_pretty(bloat_size::numeric) as bloat_size_pretty,
69-
bloat_ratio as "bloat_ratio, %",
70-
fillfactor,
71-
is_na,
72-
real_size - bloat_size as live_data_size
73-
from data
74-
order by bloat_size desc
67+
select
68+
case is_na when true then 'TRUE' else '' end as is_na,
69+
coalesce(nullif(schema_name, 'public') || '.', '') || table_name as table,
70+
pg_size_pretty(real_size::numeric) as size,
71+
pg_size_pretty(extra_size::numeric)::text || ' (' || round(extra_ratio::numeric, 2)::text || '%)' as extra_estimated,
72+
pg_size_pretty(bloat_size::numeric)::text || ' (' || round(bloat_ratio::numeric, 2)::text || '%)' as bloat_estimated,
73+
fillfactor,
74+
pg_size_pretty((real_size - bloat_size)::numeric) as live
75+
\if :postgresdba_extended
76+
,
77+
real_size as real_size_raw,
78+
extra_size as extra_size_raw,
79+
bloat_size as bloat_size_raw,
80+
real_size - bloat_size as live_data_size_raw
81+
\endif
82+
from step4
83+
order by real_size desc nulls last
7584
;
7685

86+
/*
87+
Author of the original version:
88+
2015, Jehan-Guillaume (ioguix) de Rorthais
89+
90+
License of the original version:
91+
92+
Redistribution and use in source and binary forms, with or without
93+
modification, are permitted provided that the following conditions are met:
94+
95+
* Redistributions of source code must retain the above copyright notice, this
96+
list of conditions and the following disclaimer.
97+
98+
* Redistributions in binary form must reproduce the above copyright notice,
99+
this list of conditions and the following disclaimer in the documentation
100+
and/or other materials provided with the distribution.
101+
102+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
103+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
104+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
105+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
106+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
107+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
108+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
109+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
110+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
111+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
112+
*/

start.psql

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
2+
select coalesce(current_setting('postgresdba.extended', true), 'off') = 'on' as postgresdba_extended \gset
13
\echo '\033[1;35mMenu:\033[0m'
24
\echo ' 1 – Basic Node Information (master/replica, lag, DB size, tmp files)'
35
\echo ' 2 – General Table Size Information'
@@ -34,56 +36,56 @@ select
3436
\echo 'Bye!'
3537
\echo
3638
\elif :d_step_is_1
37-
\i ./sql/1_basic.sql
39+
\ir ./sql/1_basic.sql
3840
\prompt 'Press <Enter> to continue…' d_dummy
39-
\i ./start.psql
41+
\ir ./start.psql
4042
\elif :d_step_is_2
41-
\i ./sql/2_table_sizes.sql
43+
\ir ./sql/2_table_sizes.sql
4244
\prompt 'Press <Enter> to continue…' d_dummy
43-
\i ./start.psql
45+
\ir ./start.psql
4446
\elif :d_step_is_b1
45-
\i ./sql/b1_table_estimation.sql
47+
\ir ./sql/b1_table_estimation.sql
4648
\prompt 'Press <Enter> to continue…' d_dummy
47-
\i ./start.psql
49+
\ir ./start.psql
4850
\elif :d_step_is_b2
49-
\i ./sql/b2_btree_estimation.sql
51+
\ir ./sql/b2_btree_estimation.sql
5052
\prompt 'Press <Enter> to continue…' d_dummy
51-
\i ./start.psql
53+
\ir ./start.psql
5254
\elif :d_step_is_b3
53-
\i ./sql/b3_table_pgstattuple.sql
55+
\ir ./sql/b3_table_pgstattuple.sql
5456
\prompt 'Press <Enter> to continue…' d_dummy
55-
\i ./start.psql
57+
\ir ./start.psql
5658
\elif :d_step_is_b4
57-
\i ./sql/b4_btree_pgstattuple.sql
59+
\ir ./sql/b4_btree_pgstattuple.sql
5860
\prompt 'Press <Enter> to continue…' d_dummy
59-
\i ./start.psql
61+
\ir ./start.psql
6062
\elif :d_step_is_b5
61-
\i ./sql/b5_tables_no_stats.sql
63+
\ir ./sql/b5_tables_no_stats.sql
6264
\prompt 'Press <Enter> to continue…' d_dummy
63-
\i ./start.psql
65+
\ir ./start.psql
6466
\elif :d_step_is_i1
65-
\i ./sql/i1_rare_indexes.sql
67+
\ir ./sql/i1_rare_indexes.sql
6668
\prompt 'Press <Enter> to continue…' d_dummy
67-
\i ./start.psql
69+
\ir ./start.psql
6870
\elif :d_step_is_i2
69-
\i ./sql/i2_redundant_indexes.sql
71+
\ir ./sql/i2_redundant_indexes.sql
7072
\prompt 'Press <Enter> to continue…' d_dummy
71-
\i ./start.psql
73+
\ir ./start.psql
7274
\elif :d_step_is_i3
73-
\i ./sql/i3_non_indexed_fks.sql
75+
\ir ./sql/i3_non_indexed_fks.sql
7476
\prompt 'Press <Enter> to continue…' d_dummy
75-
\i ./start.psql
77+
\ir ./start.psql
7678
\elif :d_step_is_s1
77-
\i ./sql/s1_pg_stat_statements_top_total.sql
79+
\ir ./sql/s1_pg_stat_statements_top_total.sql
7880
\prompt 'Press <Enter> to continue…' d_dummy
79-
\i ./start.psql
81+
\ir ./start.psql
8082
\elif :d_step_is_s2
81-
\i ./sql/s2_pg_stat_statements_report.sql
83+
\ir ./sql/s2_pg_stat_statements_report.sql
8284
\prompt 'Press <Enter> to continue…' d_dummy
83-
\i ./start.psql
85+
\ir ./start.psql
8486
\else
8587
\echo
8688
\echo '\033[1;31mError:\033[0m Unknown option! Try again.'
8789
\echo
88-
\i ./start.psql
90+
\ir ./start.psql
8991
\endif

0 commit comments

Comments
 (0)