РЕДАКТИРАНЕ :така, написах заявката по-долу и след това си помислих... "чакай, Postgresql изисква целевите външни ключове да имат уникални индекси." Така че предполагам, че не съм разбрал какво имаш предвид? Можете да използвате заявката по-долу, за да проверите дали източникът от вашите външни ключове имат индекси, като замените "conrelid" с "confrelid" и "conkey" с "confkey" (да, да, няма псевдоними в заявката...)
Е, предполагам, че трябва да е възможно да преминете през системните каталози... Както обикновено, най-доброто ръководство за системните каталози е да използвате psql и да направите "\set ECHO_HIDDEN 1" и след това да видите какъв SQL генерира за интересни "\ d" команди. Ето SQL, използван за намиране на външни ключове за таблица ("\d име на таблица"):
-- $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;
Изглежда, че pg_constraint има колони conkey
и confkey
които изглеждат така, сякаш може да са номерата на колоните, в които е дефиниран ключът. Вероятно confkey
е номерата на колоните във външната таблица, тъй като не е нула само за външни ключове. Освен това ми отне известно време, за да разбера, че това е SQL за показване на рефериране на външни ключове дадената таблица. Което така или иначе искаме.
Така че нещо, което тази заявка показва, че данните започват да се оформят:
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
Ще използвам 8.4 функции като unnest ... може да успеете да се справите без него.
В крайна сметка получих:
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, ' ')
Добре, това чудовище отпечатва командите на кандидат индекса и се опитва да ги съпостави със съществуващите индекси. Така че можете просто да добавите „където indexrelid е null“ в края, за да получите командите за създаване на индекси, които изглежда не съществуват.
Тази заявка не се справя много добре с многоколонни външни ключове; но imho, ако ги използвате, заслужавате проблеми.
ПО-КЪСНО РЕДАКТИРАНЕ :ето заявката с предложените редакции в горната част. Така че това показва командите за създаване на индекси, които не съществуват, в колони, които са източник на чужд ключ (а не негова цел).
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
Моят опит показва, че това всъщност не е толкова полезно. Предлага създаване на индекси за неща като референтни кодове, които наистина не се нуждаят от индексиране.