EDYTUJ :więc napisałem zapytanie poniżej, a potem pomyślałem... "poczekaj, Postgresql wymaga, aby cele kluczy obcych miały unikalne indeksy." Więc chyba źle zrozumiałem, o co ci chodziło? Możesz użyć poniższego zapytania, aby sprawdzić, czy źródło Twoich kluczy obcych ma indeksy, zastępując „conrelid” za „confrelid” i „conkey” za „confkey” (tak, tak, w zapytaniu nie ma aliasów...)
Cóż, chyba powinno dać się przejrzeć katalogi systemowe... Jak zwykle najlepszym przewodnikiem po katalogach systemowych jest użycie psql i zrobienie "\set ECHO_HIDDEN 1" a potem zobaczenie jaki SQL generuje dla ciekawości "\ d" polecenia. Oto kod SQL używany do znalezienia kluczy obcych dla tabeli ("\d nazwa_tabeli") :
-- $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;
Wygląda na to, że pg_constraint ma kolumny conkey
i confkey
które wyglądają tak, jakby mogły być numerami kolumn, w poprzek których zdefiniowany jest klucz. Prawdopodobnie confkey
to numery kolumn w tabeli obcej, ponieważ nie ma wartości null tylko dla kluczy obcych. Zajęło mi też trochę czasu, aby zdać sobie sprawę, że jest to SQL do pokazywania kluczy obcych odwołujących się podanej tabeli. A i tak tego chcemy.
Więc coś, co to zapytanie pokazuje, że dane zaczynają nabierać kształtu:
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
Będę używał funkcji 8.4, takich jak unnest ... możesz się obejść bez.
Skończyło się na:
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, ta potworność drukuje polecenia indeksów kandydujących i próbuje dopasować je do istniejących indeksów. Możesz więc po prostu dodać na końcu „gdzie indexrelid is null”, aby uzyskać polecenia tworzenia indeksów, które wydają się nie istnieć.
To zapytanie nie radzi sobie zbyt dobrze z wielokolumnowymi kluczami obcymi; ale imho, jeśli ich używasz, zasługujesz na kłopoty.
PÓŹNIEJSZE EDYTOWANIE :oto zapytanie z proponowanymi edycjami u góry. To pokazuje polecenia do tworzenia indeksów, które nie istnieją, w kolumnach, które są źródłem klucza obcego (nie jego celem).
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
Z mojego doświadczenia wynika, że to nie jest aż tak przydatne. Sugeruje tworzenie indeksów dla takich rzeczy, jak kody referencyjne, które naprawdę nie muszą być indeksowane.