PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

PostgreSQL:Como indexar todas as chaves estrangeiras?


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.