1
1
${CHECK_HOST_CMD} " ${_PSQL} -f -" << SQL
2
2
with fk_indexes as (
3
3
select
4
- schemaname as schema_name,
5
- (indexrelid::regclass)::text as index_name,
6
- (relid::regclass)::text as table_name,
4
+ n.nspname as schema_name,
5
+ ci.relname as index_name,
6
+ cr.relname as table_name,
7
7
(confrelid::regclass)::text as fk_table_ref,
8
8
array_to_string(indclass, ', ') as opclasses
9
- from
10
- pg_stat_user_indexes
11
- join pg_index using (indexrelid)
12
- left join pg_constraint
13
- on array_to_string(indkey, ',') = array_to_string(conkey, ',')
14
- and schemaname = (connamespace::regnamespace)::text
15
- and conrelid = relid
16
- and contype = 'f'
17
- where idx_scan = 0
18
- and indisunique is false
19
- and conkey is not null --conkey is not null then true else false end as is_fk_idx
9
+ from pg_index i
10
+ join pg_class ci on ci.oid = i.indexrelid and ci.relkind = 'i'
11
+ join pg_class cr on cr.oid = i.indrelid and cr.relkind = 'r'
12
+ join pg_namespace n on n.oid = ci.relnamespace
13
+ join pg_constraint cn on cn.conrelid = cr.oid
14
+ left join pg_stat_user_indexes si on si.indexrelid = i.indexrelid
15
+ where
16
+ contype = 'f'
17
+ and i.indisunique is false
18
+ and conkey is not null
19
+ and ci.relpages > 100
20
+ and si.idx_scan < 10
20
21
), table_scans as (
21
22
select relid,
22
23
tables.idx_scan + tables.seq_scan as all_scans,
23
24
( tables.n_tup_ins + tables.n_tup_upd + tables.n_tup_del ) as writes,
24
25
pg_relation_size(relid) as table_size
25
26
from pg_stat_user_tables as tables
27
+ join pg_class c on c.oid = relid
28
+ where c.relpages > 100
26
29
), all_writes as (
27
30
select sum(writes) as total_writes
28
31
from table_scans
29
32
), indexes as (
30
33
select
31
- idx_stat.relid ,
32
- idx_stat .indexrelid,
33
- idx_stat.schemaname as schema_name,
34
- idx_stat .relname as table_name,
35
- idx_stat.indexrelname as index_name,
36
- quote_ident(idx_stat.schemaname ) as formated_schema_name,
37
- quote_ident(idx_stat.indexrelname ) as formated_index_name,
38
- quote_ident(idx_stat .relname) as formated_table_name,
39
- coalesce(nullif(quote_ident(idx_stat.schemaname ), 'public') || '.', '') || quote_ident(idx_stat .relname) as formated_relation_name,
40
- idx_stat .idx_scan,
41
- pg_relation_size(idx_stat .indexrelid) as index_bytes,
42
- indexdef ~* 'using btree' as idx_is_btree ,
43
- pg_get_indexdef(pg_index.indexrelid ) as index_def ,
44
- array_to_string(pg_index.indclass, ', ' ) as opclasses
45
- from pg_stat_user_indexes as idx_stat
46
- join pg_index
47
- using ( indexrelid)
48
- join pg_indexes as indexes
49
- on idx_stat.schemaname = indexes.schemaname
50
- and idx_stat.relname = indexes.tablename
51
- and idx_stat.indexrelname = indexes.indexname
34
+ i.indrelid ,
35
+ i .indexrelid,
36
+ n.nspname as schema_name,
37
+ cr .relname as table_name,
38
+ ci.relname as index_name,
39
+ quote_ident(n.nspname ) as formated_schema_name,
40
+ quote_ident(ci.relname ) as formated_index_name,
41
+ quote_ident(cr .relname) as formated_table_name,
42
+ coalesce(nullif(quote_ident(n.nspname ), 'public') || '.', '') || quote_ident(cr .relname) as formated_relation_name,
43
+ si .idx_scan,
44
+ pg_relation_size(i .indexrelid) as index_bytes,
45
+ ci.relpages ,
46
+ (case when a.amname = 'btree' then true else false end ) as idx_is_btree ,
47
+ pg_get_indexdef(i.indexrelid ) as index_def,
48
+ array_to_string(i.indclass, ', ') as opclasses
49
+ from pg_index i
50
+ join pg_class ci on ci.oid = i. indexrelid and ci.relkind = 'i'
51
+ join pg_class cr on cr.oid = i.indrelid and cr.relkind = 'r'
52
+ join pg_namespace n on n.oid = ci.relnamespace
53
+ join pg_am a ON ci.relam = a.oid
54
+ left join pg_stat_user_indexes si on si.indexrelid = i.indexrelid
52
55
where
53
- pg_index.indisunique = false
54
- and pg_index.indisvalid = true
56
+ i.indisunique = false
57
+ and i.indisvalid = true
58
+ and ci.relpages > 100
55
59
), index_ratios as (
56
60
select
57
61
i.indexrelid as index_id,
@@ -67,6 +71,7 @@ with fk_indexes as (
67
71
as scans_per_write,
68
72
index_bytes as index_size_bytes,
69
73
table_size as table_size_bytes,
74
+ i.relpages,
70
75
idx_is_btree,
71
76
index_def,
72
77
formated_index_name,
@@ -78,9 +83,9 @@ with fk_indexes as (
78
83
from indexes i
79
84
left join fk_indexes fi on
80
85
fi.fk_table_ref = i.table_name
86
+ and fi.schema_name = i.schema_name
81
87
and fi.opclasses like (i.opclasses || '%')
82
- join table_scans
83
- using (relid)
88
+ join table_scans ts on ts.relid = i.indrelid
84
89
),
85
90
-- Never used indexes
86
91
never_used_indexes as (
@@ -163,8 +168,9 @@ index_data as (
163
168
*,
164
169
indkey::text as columns,
165
170
array_to_string(indclass, ', ') as opclasses
166
- from pg_index
167
- where indisvalid = true
171
+ from pg_index i
172
+ join pg_class ci on ci.oid = i.indexrelid and ci.relkind = 'i'
173
+ where indisvalid = true and ci.relpages > 100
168
174
), redundant_indexes as (
169
175
select
170
176
i2.indexrelid as index_id,
@@ -174,13 +180,14 @@ index_data as (
174
180
irel.relname AS index_name,
175
181
am1.amname as access_method,
176
182
(i1.indexrelid::regclass)::text as reason,
183
+ i1.indexrelid as reason_index_id,
177
184
pg_get_indexdef(i1.indexrelid) main_index_def,
178
185
pg_size_pretty(pg_relation_size(i1.indexrelid)) main_index_size,
179
186
pg_get_indexdef(i2.indexrelid) index_def,
180
187
pg_relation_size(i2.indexrelid) index_size_bytes,
181
188
s.idx_scan as index_usage,
182
189
quote_ident(tnsp.nspname) as formated_schema_name,
183
- quote_ident(irel.relname) as formated_index_name,
190
+ coalesce(nullif(quote_ident(tnsp.nspname), 'public') || '.', '') || quote_ident(irel.relname) as formated_index_name,
184
191
quote_ident(trel.relname) AS formated_table_name,
185
192
coalesce(nullif(quote_ident(tnsp.nspname), 'public') || '.', '') || quote_ident(trel.relname) as formated_relation_name,
186
193
i2.opclasses
@@ -218,6 +225,28 @@ index_data as (
218
225
left join fk_indexes fi on
219
226
fi.fk_table_ref = ri.table_name
220
227
and fi.opclasses like (ri.opclasses || '%')
228
+ ),
229
+ -- Cut recursive links
230
+ redundant_indexes_tmp_num as (
231
+ select row_number() over () num, rig.*
232
+ from redundant_indexes_fk rig
233
+ ), redundant_indexes_tmp_links as (
234
+ select
235
+ ri1.*,
236
+ ri2.num as r_num
237
+ from redundant_indexes_tmp_num ri1
238
+ left join redundant_indexes_tmp_num ri2 on ri2.reason_index_id = ri1.index_id and ri1.reason_index_id = ri2.index_id
239
+ ), redundant_indexes_tmp_cut as (
240
+ select
241
+ *
242
+ from redundant_indexes_tmp_links
243
+ where num < r_num or r_num is null
244
+ ), redundant_indexes_cut_grouped as (
245
+ select
246
+ distinct(num),
247
+ *
248
+ from redundant_indexes_tmp_cut
249
+ order by index_size_bytes desc
221
250
), redundant_indexes_grouped as (
222
251
select
223
252
index_id,
@@ -237,7 +266,7 @@ index_data as (
237
266
formated_table_name,
238
267
formated_relation_name,
239
268
supports_fk
240
- from redundant_indexes_fk
269
+ from redundant_indexes_cut_grouped
241
270
group by
242
271
index_id,
243
272
table_size_bytes,
@@ -258,8 +287,7 @@ index_data as (
258
287
select row_number() over () num, rig.*
259
288
from redundant_indexes_grouped rig
260
289
limit ${ROWS_LIMIT}
261
- ),
262
- redundant_indexes_json as (
290
+ ), redundant_indexes_json as (
263
291
select
264
292
json_object_agg(rin.schema_name || '.' || rin.index_name, rin) as json
265
293
from redundant_indexes_num rin
0 commit comments