Skip to content

Commit 58816ce

Browse files
author
Shane Borden
committed
add unused indexes script
1 parent 0a79673 commit 58816ce

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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+
16+
WITH table_scans as (
17+
SELECT relid,
18+
tables.idx_scan + tables.seq_scan as all_scans,
19+
( tables.n_tup_ins + tables.n_tup_upd + tables.n_tup_del ) as writes,
20+
pg_relation_size(relid) as table_size
21+
FROM pg_stat_all_tables as tables
22+
WHERE schemaname not in ('pg_toast','pg_catalog','partman')
23+
),
24+
all_writes as (
25+
SELECT sum(writes) as total_writes
26+
FROM table_scans
27+
),
28+
indexes as (
29+
SELECT idx_stat.relid, idx_stat.indexrelid,
30+
idx_stat.schemaname, idx_stat.relname as tablename,
31+
idx_stat.indexrelname as indexname,
32+
idx_stat.idx_scan,
33+
pg_relation_size(idx_stat.indexrelid) as index_bytes,
34+
indexdef ~* 'USING btree' AS idx_is_btree
35+
FROM pg_stat_user_indexes as idx_stat
36+
JOIN pg_index
37+
USING (indexrelid)
38+
JOIN pg_indexes as indexes
39+
ON idx_stat.schemaname = indexes.schemaname
40+
AND idx_stat.relname = indexes.tablename
41+
AND idx_stat.indexrelname = indexes.indexname
42+
WHERE pg_index.indisunique = FALSE
43+
),
44+
index_ratios AS (
45+
SELECT schemaname, tablename, indexname,
46+
idx_scan, all_scans,
47+
round(( CASE WHEN all_scans = 0 THEN 0.0::NUMERIC
48+
ELSE idx_scan::NUMERIC/all_scans * 100 END),2) as index_scan_pct,
49+
writes,
50+
round((CASE WHEN writes = 0 THEN idx_scan::NUMERIC ELSE idx_scan::NUMERIC/writes END),2)
51+
as scans_per_write,
52+
pg_size_pretty(index_bytes) as index_size_pretty,
53+
pg_size_pretty(table_size) as table_size,
54+
idx_is_btree,
55+
index_bytes as index_size_bytes
56+
FROM indexes
57+
JOIN table_scans
58+
USING (relid)
59+
),
60+
index_groups AS (
61+
SELECT 'Never Used Indexes' as reason, *, 1 as grp
62+
FROM index_ratios
63+
WHERE
64+
idx_scan = 0
65+
and idx_is_btree
66+
UNION ALL
67+
SELECT 'Low Scans, High Writes' as reason, *, 2 as grp
68+
FROM index_ratios
69+
WHERE
70+
scans_per_write <= 1
71+
and index_scan_pct < 10
72+
and idx_scan > 0
73+
and writes > 100
74+
and idx_is_btree
75+
UNION ALL
76+
SELECT 'Seldom Used Large Indexes' as reason, *, 3 as grp
77+
FROM index_ratios
78+
WHERE
79+
index_scan_pct < 5
80+
and scans_per_write > 1
81+
and idx_scan > 0
82+
and idx_is_btree
83+
and index_size_bytes > 100000000
84+
UNION ALL
85+
SELECT 'High-Write Large Non-Btree' as reason, index_ratios.*, 4 as grp
86+
FROM index_ratios, all_writes
87+
WHERE
88+
( writes::NUMERIC / ( total_writes + 1 ) ) > 0.02
89+
AND NOT idx_is_btree
90+
AND index_size_bytes > 100000000
91+
ORDER BY grp, index_size_bytes DESC )
92+
SELECT reason, schemaname, tablename, indexname,
93+
index_scan_pct, scans_per_write, index_size_pretty,index_size_bytes, table_size
94+
FROM index_groups
95+
WHERE tablename like '%'
96+
ORDER BY reason, index_size_bytes,table_size;

0 commit comments

Comments
 (0)