REDIGER :så jeg skrev nedenstående forespørgsel og tænkte så... "vent på, Postgresql kræver, at udenlandske nøglemål skal have unikke indekser." Så jeg har vist misforstået hvad du mente? Du kan bruge nedenstående forespørgsel til at kontrollere, at kilden af dine fremmednøgler har indekser ved at erstatte "conrelid" med "confrelid" og "conkey" for "confkey" (ja, ja, ingen aliaser i forespørgslen...)
Tja, det burde vel være muligt at gennemgå systemkatalogerne... Som sædvanlig er den bedste guide til systemkatalogerne at bruge psql og lave "\set ECHO_HIDDEN 1" og så se hvilken SQL det genererer for interessant "\ d" kommandoer. Her er den SQL, der bruges til at finde fremmednøglerne til en tabel ("\d tabelnavn") :
-- $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;
Det ser ud til, at pg_constraint har kolonner conkey
og confkey
der ser ud som om de kunne være de kolonnenumre, som nøglen er defineret på tværs af. Sandsynligvis confkey
er kolonnenumrene i den fremmede tabel, da den kun er ikke-nul for fremmede nøgler. Det tog mig også et stykke tid at indse, at dette er SQL'en til at vise fremmednøgler henvisning den givne tabel. Hvilket er det, vi alligevel ønsker.
Så noget af denne forespørgsel viser, at dataene begynder at tage form:
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
Jeg kommer til at bruge 8.4-funktioner som unnest ... du måske kan klare dig uden.
Jeg endte med:
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, denne monstrøsitet udskriver kandidatindekskommandoerne og forsøger at matche dem med eksisterende indekser. Så du kan blot tilføje "hvor indexrelid er null" i slutningen for at få kommandoerne til at oprette indekser, der ikke ser ud til at eksistere.
Denne forespørgsel beskæftiger sig ikke særlig godt med fremmednøgler med flere kolonner; men imho hvis du bruger dem, fortjener du problemer.
SENERE REDIGERING :her er forespørgslen med de foreslåede redigeringer øverst indsat. Så dette viser kommandoerne til at oprette indekser, der ikke eksisterer, på kolonner, der er kilden til en fremmednøgle (ikke dens mål).
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
Min erfaring er, at det ikke er så nyttigt. Det foreslår, at der oprettes indekser for ting som referencekoder, der virkelig ikke behøver at blive indekseret.