EDITAR :então, escrevi a consulta abaixo e pensei... "espere, o Postgresql exige que os destinos de chave estrangeira tenham índices exclusivos." Então acho que não entendi o que você quis dizer? Você pode usar a consulta abaixo para verificar se a fonte das suas chaves estrangeiras têm índices substituindo "conrelid" por "confrelid" e "conkey" por "confkey" (sim, sim, sem aliases na consulta ...)
Bem, acho que deve ser possível percorrer os catálogos do sistema... Como de costume, o melhor guia para os catálogos do sistema é usar o psql e fazer "\set ECHO_HIDDEN 1" e depois ver qual SQL ele gera para "\ comandos d". Aqui está o SQL usado para encontrar as chaves estrangeiras para uma tabela ("\d tablename"):
-- $1 is the table OID, e.g. 'tablename'::regclass
SELECT conname, conrelid::pg_catalog.regclass,
pg_catalog.pg_get_constraintdef(c.oid, true) as condef
FROM pg_catalog.pg_constraint c
WHERE c.confrelid = $1 AND c.contype = 'f' ORDER BY 1;
Parece que pg_constraint tem colunas
conkey
e confkey
que parecem ser os números das colunas em que a chave é definida. Provavelmente confkey
é os números das colunas na tabela estrangeira, pois só é não nulo para chaves estrangeiras. Além disso, demorei um pouco para perceber que este é o SQL para mostrar as chaves estrangeiras referência a tabela dada. Que é o que queremos de qualquer maneira. Então, algo que esta consulta mostra os dados começando a tomar forma:
select confrelid, conname, column_index, attname
from pg_attribute
join (select confrelid::regclass, conname, unnest(confkey) as column_index
from pg_constraint
where confrelid = 'ticket_status'::regclass) fkey
on fkey.confrelid = pg_attribute.attrelid
and fkey.column_index = pg_attribute.attnum
Vou usar recursos 8.4 como unnest ... você pode ser capaz de passar sem.
Acabei com:
select pg_index.indexrelid::regclass, 'create index ' || relname || '_' ||
array_to_string(column_name_list, '_') || '_idx on ' || confrelid ||
' (' || array_to_string(column_name_list, ',') || ')'
from (select distinct
confrelid,
array_agg(attname) column_name_list,
array_agg(attnum) as column_list
from pg_attribute
join (select confrelid::regclass,
conname,
unnest(confkey) as column_index
from (select distinct
confrelid, conname, confkey
from pg_constraint
join pg_class on pg_class.oid = pg_constraint.confrelid
join pg_namespace on pg_namespace.oid = pg_class.relnamespace
where nspname !~ '^pg_' and nspname <> 'information_schema'
) fkey
) fkey
on fkey.confrelid = pg_attribute.attrelid
and fkey.column_index = pg_attribute.attnum
group by confrelid, conname
) candidate_index
join pg_class on pg_class.oid = candidate_index.confrelid
left join pg_index on pg_index.indrelid = confrelid
and indkey::text = array_to_string(column_list, ' ')
OK, esta monstruosidade imprime os comandos do índice candidato e tenta combiná-los com os índices existentes. Assim, você pode simplesmente adicionar "where indexrelid is null" no final para obter os comandos para criar índices que parecem não existir.
Essa consulta não lida muito bem com chaves estrangeiras de várias colunas; mas imho se você estiver usando isso, você merece problemas.
EDITAR MAIS TARDE :aqui está a consulta com as edições propostas no topo. Então, isso mostra os comandos para criar índices que não existem, em colunas que são a origem de uma chave estrangeira (não seu destino).
select pg_index.indexrelid::regclass, 'create index ' || relname || '_' ||
array_to_string(column_name_list, '_') || '_idx on ' || conrelid ||
' (' || array_to_string(column_name_list, ',') || ')'
from (select distinct
conrelid,
array_agg(attname) column_name_list,
array_agg(attnum) as column_list
from pg_attribute
join (select conrelid::regclass,
conname,
unnest(conkey) as column_index
from (select distinct
conrelid, conname, conkey
from pg_constraint
join pg_class on pg_class.oid = pg_constraint.conrelid
join pg_namespace on pg_namespace.oid = pg_class.relnamespace
where nspname !~ '^pg_' and nspname <> 'information_schema'
) fkey
) fkey
on fkey.conrelid = pg_attribute.attrelid
and fkey.column_index = pg_attribute.attnum
group by conrelid, conname
) candidate_index
join pg_class on pg_class.oid = candidate_index.conrelid
left join pg_index on pg_index.indrelid = conrelid
and indkey::text = array_to_string(column_list, ' ')
where indexrelid is null
Minha experiência é que isso não é realmente tão útil. Ele sugere a criação de índices para coisas como códigos de referência que realmente não precisam ser indexados.