Ir para o conteúdo principal

Identificar índices não utilizados (ou não eficientes)

with
table_scans as (
select
	tables.relid as relid,
	tables.schemaname as schemaname,
	tables.relname as tablename,
	tables.idx_scan as table_idx_scan_count,
	tables.idx_tup_fetch as table_idx_tup_fetch,
	tables.seq_scan as table_seq_scan_count,
	tables.seq_tup_read as table_seq_tup_read,
	tables.idx_scan + tables.seq_scan as table_sum_all_scans,
	tables.n_tup_ins as table_write_insert_count,
	tables.n_tup_upd as table_write_update_count,
	tables.n_tup_del as table_write_delete_count,
	tables.n_tup_ins + tables.n_tup_upd + tables.n_tup_del as table_sum_all_writes,
	tables.n_tup_hot_upd as table_tup_hot_upd_count,
	tables.n_live_tup as table_live_tup_count,
	pg_relation_size(relid) as table_bytes
from
	pg_stat_user_tables as tables
),
database_writes as (
select
	sum(table_sum_all_writes) as database_sum_all_writes
from
	table_scans
),
indexes as (
select
	idx_stat.relid as relid,
	idx_stat.indexrelid as indexrelid,
	idx_stat.schemaname as schemaname,
	idx_stat.relname as tablename,
	idx_stat.indexrelname as indexname,
	idx_stat.idx_scan as index_idx_scan_count,
	idx_stat.idx_tup_read as index_idx_tup_read,
	idx_stat.idx_tup_fetch as index_idx_tup_fetch,
	pg_relation_size(idx_stat.indexrelid) as index_bytes,
	indexes.indexdef ~* 'USING btree' as idx_is_btree
from
	pg_stat_user_indexes as idx_stat
join pg_index as pg_index
		using (indexrelid)
join pg_indexes as indexes
on
	idx_stat.schemaname = indexes.schemaname
	and idx_stat.relname = indexes.tablename
	and idx_stat.indexrelname = indexes.indexname
where
	pg_index.indisunique = false
),
index_ratios as (
select
	indexes.schemaname as schemaname,
	indexes.tablename as tablename,
	indexes.indexname as indexname,
	indexes.index_idx_scan_count as index_idx_scan_count,
	indexes.index_idx_tup_read as index_idx_tup_read,
	indexes.index_idx_tup_fetch as index_idx_tup_fetch,
	round(case when indexes.index_idx_scan_count = 0 or table_scans.table_live_tup_count = 0
then -1 :: numeric
  else indexes.index_idx_tup_fetch :: numeric / indexes.index_idx_scan_count / table_scans.table_live_tup_count * 100 end, 2) as idx_pct_table_fetched,
	table_scans.table_idx_scan_count as table_idx_scan_count,
	table_scans.table_seq_scan_count as table_seq_scan_count,
	table_scans.table_seq_tup_read as table_seq_tup_read,
	table_scans.table_sum_all_scans as table_sum_all_scans,
	round((case when table_scans.table_sum_all_scans = 0
then -1 :: numeric
   else indexes.index_idx_scan_count :: numeric / table_scans.table_sum_all_scans * 100 end), 2) as index_scan_pct,
	table_scans.table_write_insert_count as table_write_insert_count,
	table_scans.table_write_update_count as table_write_update_count,
	table_scans.table_write_delete_count as table_write_delete_count,
	table_scans.table_sum_all_writes as table_sum_all_writes,
	round((case when table_scans.table_sum_all_writes = 0
then indexes.index_idx_scan_count :: numeric
   else indexes.index_idx_scan_count :: numeric / table_scans.table_sum_all_writes end), 2) as scans_per_write,
	table_scans.table_tup_hot_upd_count as table_tup_hot_upd_count,
	table_scans.table_live_tup_count as table_live_tup_count,
	indexes.index_bytes as index_bytes,
	pg_size_pretty(indexes.index_bytes) as index_size,
	table_scans.table_bytes as table_bytes,
	pg_size_pretty(table_scans.table_bytes) as table_size,
	indexes.idx_is_btree as idx_is_btree
from
	indexes
join table_scans
		using (relid)
),
index_groups as (
select
	1 as grp,
	'Never Used Indexes' as reason,
	*
from
	index_ratios
where
	index_ratios.index_idx_scan_count = 0
	and index_ratios.idx_is_btree
union all
select
	2 as grp,
	'Low Scans, High Writes' as reason,
	*
from
	index_ratios
where
	scans_per_write <= 1
	and index_scan_pct < 10
	and index_idx_scan_count > 0
	and table_sum_all_writes > 100
	and idx_is_btree
union all
select
	3 as grp,
	'Seldom Used Large Indexes' as reason,
	*
from
	index_ratios
where
	index_scan_pct < 5
	and scans_per_write > 1
	and index_idx_scan_count > 0
	and idx_is_btree
	and index_bytes > 100000000
union all
select
	4 as grp,
	'High-Write Large Non-Btree' as reason,
	index_ratios.*
from
	index_ratios,
	database_writes
where
	(table_sum_all_writes :: numeric / coalesce(nullif(database_sum_all_writes, 0), 1)) > 0.02
		and not idx_is_btree
		and index_bytes > 100000000
union all
	select
		5 as grp,
		'(+) Sem Efetividade' as reason,
		index_ratios.*
	from
		index_ratios
	where
		idx_is_btree
		and index_idx_scan_count > 0
		and idx_pct_table_fetched > 20
union all
	select
		6 as grp,
		'(+) Índice Médio (100MB a 500MB)' as reason,
		index_ratios.*
	from
		index_ratios
	where
		index_bytes >= 100000000
		and index_bytes < 500000000
union all
	select
		7 as grp,
		'(+) Índice Grande (500MB a 1 GB)' as reason,
		index_ratios.*
	from
		index_ratios
	where
		index_bytes >= 500000000
		and index_bytes < 1000000000
union all
	select
		8 as grp,
		'(+) Índice Enorme (mais de 1 GB)' as reason,
		index_ratios.*
	from
		index_ratios
	where
		index_bytes >= 1000000000
	order by
		grp,
		index_bytes desc
)
select
	reason,
	schemaname,
	tablename,
	indexname,
	table_size,
	index_size
from
	index_groups