Skip to content

Commit c9da23f

Browse files
author
Shane Borden
committed
add additional files and diag scripts
1 parent df174e5 commit c9da23f

9 files changed

+469
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- Copyright 2025 shaneborden
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- https://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
/* find options like search_path assigned to users or databases */
16+
SELECT coalesce(role.rolname, 'database wide') as role,
17+
coalesce(db.datname, 'cluster wide') as database,
18+
setconfig as what_changed
19+
FROM pg_db_role_setting role_setting
20+
LEFT JOIN pg_roles role ON role.oid = role_setting.setrole
21+
LEFT JOIN pg_database db ON db.oid = role_setting.setdatabase;
22+
23+
/* or from psql */
24+
\drds
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- Copyright 2024 shaneborden
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- https://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
SELECT
16+
(SELECT max(age(backend_xmin)) FROM pg_stat_activity) as oldest_running_xact,
17+
(SELECT max(age(transaction)) FROM pg_prepared_xacts) as oldest_prepared_xact,
18+
(SELECT max(age(xmin)) FROM pg_replication_slots) as oldest_replication_slot,
19+
(SELECT max(age(backend_xmin)) FROM pg_stat_replication) as oldest_replica_xact
20+
;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
-- Copyright 2024 shaneborden
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- https://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
/* Determine which pids map to the oldest xmin age */
16+
SELECT
17+
pid,
18+
usename,
19+
datname,
20+
client_addr,
21+
state,
22+
now() - backend_start connection_total_time,
23+
now() - state_change time_in_state,
24+
now() - xact_start time_in_xact,
25+
now() - query_start time_in_query,
26+
wait_event,
27+
left (query, 40),
28+
max(age(backend_xmin))
29+
FROM
30+
pg_stat_activity
31+
WHERE
32+
1=1
33+
AND backend_xmin IS NOT NULL
34+
GROUP BY
35+
pid,
36+
usename,
37+
datname,
38+
client_addr,
39+
state,
40+
now() - backend_start,
41+
now() - state_change,
42+
now() - xact_start,
43+
now() - query_start,
44+
wait_event,
45+
left (query, 40)
46+
ORDER BY
47+
max(age(backend_xmin)) DESC;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* Set AlloyDB Flag to have advisor run 1x per hour */
2+
google_db_advisor.auto_advisor_schedule = 'EVERY 1 HOURS'
3+
4+
/* Check location of extensions */
5+
(postgres@10.3.1.17:5432) [postgres] > \dx hypopg
6+
List of installed extensions
7+
Name | Version | Schema | Description
8+
--------+---------+--------+-------------
9+
hypopg | 1.3.2 | public |
10+
(postgres@10.3.1.17:5432) [postgres] > \dx google_db_advisor
11+
List of installed extensions
12+
Name | Version | Schema | Description
13+
-------------------+---------+--------+-------------
14+
google_db_advisor | 1.0 | public |
15+
16+
CREATE TABLE public.index_advisor_test (
17+
id int,
18+
value numeric,
19+
product_id int,
20+
effective_date timestamp(3)
21+
);
22+
INSERT INTO public.index_advisor_test VALUES (
23+
generate_series(0,100000000),
24+
random()*1000,
25+
random()*100,
26+
current_timestamp(3));
27+
28+
CREATE SCHEMA idx_advisor;
29+
30+
CREATE TABLE idx_advisor.index_advisor_test (
31+
id int,
32+
value numeric,
33+
product_id int,
34+
effective_date timestamp(3)
35+
);
36+
INSERT INTO idx_advisor.index_advisor_test VALUES (
37+
generate_series(0,100000000),
38+
random()*1000,
39+
random()*100,
40+
current_timestamp(3));
41+
42+
ANALYZE VERBOSE public.index_advisor_test;
43+
ANALYZE VERBOSE idx_advisor.index_advisor_test;
44+
45+
/* Run a query that could possibly benefit from an index: */
46+
47+
SET enable_ultra_fast_cache_explain_output TO ON;
48+
EXPLAIN (analyze, verbose, columnar_engine, costs, settings, buffers, wal, timing, summary, format text)
49+
select /* INDEX ADVISOR TEST */ * from public.index_advisor_test where id = 500533;
50+
51+
EXPLAIN (analyze, verbose, columnar_engine, costs, settings, buffers, wal, timing, summary, format text)
52+
select /* INDEX ADVISOR TEST */ * from idx_advisor.index_advisor_test where id = 500533;
53+
54+
55+
/* Check index advisor las run */
56+
SELECT DISTINCT recommended_indexes, query
57+
FROM google_db_advisor_workload_report r, google_db_advisor_workload_statements s
58+
WHERE r.query_id = s.query_id;
59+
60+
SELECT
61+
r.recommended_indexes,
62+
s.query
63+
FROM
64+
google_db_advisor_workload_report r,
65+
google_db_advisor_workload_statements s
66+
WHERE
67+
r.query_id = s.query_id
68+
AND r.db_id = s.db_id
69+
AND r.user_id = s.user_id
70+
AND length(r.recommended_indexes) > 0;
71+
72+
select * from google_db_advisor_workload_report_detail;
73+
74+
75+
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
-- Copyright 2024 shaneborden
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- https://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
WITH btree_index_atts AS (
16+
SELECT nspname,
17+
indexclass.relname as index_name,
18+
indexclass.reltuples,
19+
indexclass.relpages,
20+
indrelid,
21+
indexclass.relam,
22+
tableclass.relname as tablename,
23+
indexrelid as index_oid,
24+
pg_attribute.attname,
25+
pg_attribute.attnum
26+
FROM pg_index
27+
JOIN pg_class AS indexclass ON pg_index.indexrelid = indexclass.oid
28+
JOIN pg_class AS tableclass ON pg_index.indrelid = tableclass.oid
29+
JOIN pg_namespace ON pg_namespace.oid = indexclass.relnamespace
30+
JOIN pg_am ON indexclass.relam = pg_am.oid
31+
JOIN pg_attribute ON pg_attribute.attrelid = tableclass.oid
32+
AND pg_attribute.attnum = ANY(indkey)
33+
WHERE pg_am.amname = 'btree' and indexclass.relpages > 0
34+
AND nspname NOT IN ('pg_catalog','information_schema')
35+
AND tableclass.relname like '%'
36+
),
37+
index_item_sizes AS (
38+
SELECT
39+
ind_atts.nspname, ind_atts.index_name,
40+
ind_atts.reltuples, ind_atts.relpages, ind_atts.relam,
41+
indrelid AS table_oid, index_oid,
42+
current_setting('block_size')::numeric AS bs,
43+
8 AS maxalign,
44+
24 AS pagehdr,
45+
CASE WHEN max(coalesce(pg_stats.null_frac,0)) = 0
46+
THEN 2
47+
ELSE 6
48+
END AS index_tuple_hdr,
49+
sum( (1-coalesce(pg_stats.null_frac, 0)) * coalesce(pg_stats.avg_width, 1024) ) AS nulldatawidth
50+
FROM btree_index_atts AS ind_atts
51+
left JOIN pg_stats ON pg_stats.schemaname = ind_atts.nspname
52+
-- stats for regular index columns
53+
AND ( (pg_stats.tablename = ind_atts.tablename AND pg_stats.attname = ind_atts.attname)
54+
-- stats for functional indexes
55+
OR (pg_stats.tablename = ind_atts.index_name AND pg_stats.attname = ind_atts.attname))
56+
WHERE ind_atts.attnum > 0
57+
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9
58+
),
59+
index_aligned_est AS (
60+
SELECT maxalign, bs, nspname, index_name, reltuples,
61+
relpages, relam, table_oid, index_oid,
62+
coalesce (
63+
ceil (
64+
reltuples * ( 6
65+
+ maxalign
66+
- CASE
67+
WHEN index_tuple_hdr%maxalign = 0 THEN maxalign
68+
ELSE index_tuple_hdr%maxalign
69+
END
70+
+ nulldatawidth
71+
+ maxalign
72+
- CASE /* Add padding to the data to align on MAXALIGN */
73+
WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign
74+
ELSE nulldatawidth::integer%maxalign
75+
END
76+
)::numeric
77+
/ ( bs - pagehdr::NUMERIC )
78+
+1 )
79+
, 0 )
80+
as expected
81+
FROM index_item_sizes
82+
),
83+
raw_bloat AS (
84+
SELECT current_database() as dbname, nspname, pg_class.relname AS table_name, index_name,
85+
bs*(index_aligned_est.relpages)::bigint AS totalbytes, expected,
86+
CASE
87+
WHEN index_aligned_est.relpages <= expected
88+
THEN 0
89+
ELSE bs*(index_aligned_est.relpages-expected)::bigint
90+
END AS wastedbytes,
91+
CASE
92+
WHEN index_aligned_est.relpages <= expected
93+
THEN 0
94+
ELSE bs*(index_aligned_est.relpages-expected)::bigint * 100 / (bs*(index_aligned_est.relpages)::bigint)
95+
END AS realbloat,
96+
pg_relation_size(index_aligned_est.table_oid) as table_bytes,
97+
stat.idx_scan as index_scans
98+
FROM index_aligned_est
99+
JOIN pg_class ON pg_class.oid=index_aligned_est.table_oid
100+
JOIN pg_stat_user_indexes AS stat ON index_aligned_est.index_oid = stat.indexrelid
101+
),
102+
format_bloat AS (
103+
SELECT dbname as database_name, nspname as schema_name, table_name, index_name,
104+
round(realbloat) as bloat_pct, round(wastedbytes/(1024^2)::NUMERIC) as bloat_mb,
105+
round(totalbytes/(1024^2)::NUMERIC,3) as index_mb,
106+
round(table_bytes/(1024^2)::NUMERIC,3) as table_mb,
107+
index_scans
108+
FROM raw_bloat
109+
)
110+
-- final query outputting the bloated indexes
111+
-- change the where and order by to change
112+
-- what shows up as bloated
113+
SELECT *
114+
FROM format_bloat
115+
--WHERE ( bloat_pct > 50 and bloat_mb > 10 )
116+
--WHERE index_name like '%_user_id_idx'
117+
ORDER BY bloat_pct DESC NULLS LAST;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
-- Copyright 2024 shaneborden
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- https://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
-- Basis of script from https://wiki.postgresql.org/wiki/Index_Progress
16+
17+
select
18+
now(),
19+
query_start as started_at,
20+
now() - query_start as query_duration,
21+
format('[%s] %s', a.pid, a.query) as pid_and_query,
22+
index_relid::regclass as index_name,
23+
relid::regclass as table_name,
24+
(pg_size_pretty(pg_relation_size(relid))) as table_size,
25+
nullif(wait_event_type, '') || ': ' || wait_event as wait_type_and_event,
26+
phase,
27+
format(
28+
'%s (%s of %s)',
29+
coalesce((round(100 * blocks_done::numeric / nullif(blocks_total, 0), 2))::text || '%', 'N/A'),
30+
coalesce(blocks_done::text, '?'),
31+
coalesce(blocks_total::text, '?')
32+
) as blocks_progress,
33+
format(
34+
'%s (%s of %s)',
35+
coalesce((round(100 * tuples_done::numeric / nullif(tuples_total, 0), 2))::text || '%', 'N/A'),
36+
coalesce(tuples_done::text, '?'),
37+
coalesce(tuples_total::text, '?')
38+
) as tuples_progress,
39+
current_locker_pid,
40+
(select nullif(left(query, 150), '') || '...' from pg_stat_activity a where a.pid = current_locker_pid) as current_locker_query,
41+
format(
42+
'%s (%s of %s)',
43+
coalesce((round(100 * lockers_done::numeric / nullif(lockers_total, 0), 2))::text || '%', 'N/A'),
44+
coalesce(lockers_done::text, '?'),
45+
coalesce(lockers_total::text, '?')
46+
) as lockers_progress,
47+
format(
48+
'%s (%s of %s)',
49+
coalesce((round(100 * partitions_done::numeric / nullif(partitions_total, 0), 2))::text || '%', 'N/A'),
50+
coalesce(partitions_done::text, '?'),
51+
coalesce(partitions_total::text, '?')
52+
) as partitions_progress,
53+
(
54+
select
55+
format(
56+
'%s (%s of %s)',
57+
coalesce((round(100 * n_dead_tup::numeric / nullif(reltuples::numeric, 0), 2))::text || '%', 'N/A'),
58+
coalesce(n_dead_tup::text, '?'),
59+
coalesce(reltuples::int8::text, '?')
60+
)
61+
from pg_stat_all_tables t, pg_class tc
62+
where t.relid = p.relid and tc.oid = p.relid
63+
) as table_dead_tuples
64+
from pg_stat_progress_create_index p
65+
left join pg_stat_activity a on a.pid = p.pid
66+
order by p.index_relid;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
-- Copyright 2025 shaneborden
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- https://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
SELECT
16+
n.nspname AS schemaname,
17+
pgi.tablename AS tablename,
18+
c.oid::regclass::text AS index_name,
19+
pi.inhparent::regclass::text AS top_index_name,
20+
pg_total_relation_size(c.oid) AS size,
21+
pg_size_pretty(pg_total_relation_size(c.oid)) AS pretty_size
22+
FROM
23+
pg_class c
24+
JOIN pg_namespace n ON c.relnamespace = n.oid
25+
JOIN pg_indexes pgi ON pgi.indexname = c.oid::regclass::text
26+
AND pgi.schemaname = n.nspname
27+
LEFT JOIN pg_inherits pi ON c.oid = pi.inhrelid
28+
WHERE
29+
c.relkind IN ('i')
30+
AND (n.nspname NOT IN ('pg_toast')
31+
AND n.nspname LIKE '%')
32+
AND (c.oid::regclass::text LIKE '%'
33+
AND pi.inhparent::regclass::text LIKE '%')
34+
ORDER BY
35+
4 NULLS LAST;

0 commit comments

Comments
 (0)