PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL:come indicizzare tutte le chiavi esterne?

MODIFICA :quindi, ho scritto la query di seguito e poi ho pensato ... "aspetta, Postgresql richiede che gli obiettivi della chiave esterna abbiano indici univoci". Quindi immagino di aver frainteso cosa intendevi? Puoi utilizzare la query seguente per verificare che la fonte delle tue chiavi esterne hanno indici sostituendo "conrelid" per "confrelid" e "conkey" per "confkey" (sì, sì, nessun alias nella query...)

Bene, immagino che dovrebbe essere possibile scorrere i cataloghi di sistema... Come al solito, la migliore guida ai cataloghi di sistema è usare psql e fare "\set ECHO_HIDDEN 1" e quindi vedere quale SQL genera per interessanti "\ d" comandi. Ecco l'SQL utilizzato per trovare le chiavi esterne per una tabella ("\d nometabella") :

-- $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;

Sembra che pg_constraint abbia colonne conkey e confkey che sembrano essere i numeri di colonna in cui è definita la chiave. Probabilmente confkey è il numero di colonna nella tabella esterna poiché è solo non nullo per le chiavi esterne. Inoltre, mi ci è voluto un po' per rendermi conto che questo è l'SQL per mostrare le chiavi esterne riferimento la tabella data. Che è quello che vogliamo comunque.

Quindi qualcosa questa query mostra i dati che iniziano a prendere 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

Userò funzionalità 8.4 come unnest ... potresti essere in grado di cavartela senza.

Ho finito con:

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, questa mostruosità stampa i comandi di indice candidati e cerca di abbinarli agli indici esistenti. Quindi puoi semplicemente aggiungere "where indexrelid is null" alla fine per ottenere i comandi per creare indici che sembrano non esistere.

Questa query non gestisce molto bene le chiavi esterne a più colonne; ma imho se li stai usando, ti meriti problemi.

MODIFICA SUCCESSIVA :ecco la query con le modifiche proposte in alto inserite. Quindi questo mostra i comandi per creare indici che non esistono, su colonne che sono l'origine di una chiave esterna (non la sua destinazione).

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

La mia esperienza è che questo non è poi così utile. Suggerisce di creare indici per cose come codici di riferimento che in realtà non hanno bisogno di essere indicizzati.