sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL:Hur indexerar man alla främmande nycklar?

REDIGERA :så, jag skrev frågan nedan och tänkte sedan... "håll ut, Postgresql kräver att utländska nyckelmål måste ha unika index." Så jag antar att jag missuppfattade vad du menade? Du kan använda frågan nedan för att kontrollera att källan av dina främmande nycklar har index genom att ersätta "conrelid" för "confrelid" och "conkey" för "confkey" (ja, ja, inga alias i frågan...)

Tja, jag antar att det borde vara möjligt att gå igenom systemkatalogerna... Som vanligt är den bästa guiden till systemkatalogerna att använda psql och göra "\set ECHO_HIDDEN 1" och sedan se vilken SQL den genererar för intressant "\ d" kommandon. Här är SQL som används för att hitta främmande nycklar för en tabell ("\d tabellnamn") :

-- $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 verkar som att pg_constraint har kolumner conkey och confkey som ser ut att kunna vara kolumnnumren som nyckeln definieras över. Förmodligen confkey är kolumnnumren i den främmande tabellen eftersom den endast är icke-null för främmande nycklar. Det tog mig också ett tag att inse att detta är SQL-koden för att visa främmande nycklar som refererar den givna tabellen. Vilket är vad vi i alla fall vill.

Så något som den här frågan visar att data börjar ta 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

Jag kommer att använda 8.4-funktioner som unnest ... du kanske klarar dig utan.

Jag slutade 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, denna monstrositet skriver ut kandidatindexkommandona och försöker matcha dem med befintliga index. Så du kan helt enkelt lägga till "där indexrelid är null" på slutet för att få kommandona för att skapa index som inte verkar existera.

Den här frågan hanterar inte främmande nycklar med flera kolumner särskilt bra; men om du använder dem förtjänar du problem.

SENARE REDIGERING :här är frågan med de föreslagna redigeringarna högst upp. Detta visar kommandona för att skapa index som inte finns, på kolumner som är källan till en främmande nyckel (inte dess 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 erfarenhet är att det här inte är så användbart. Det föreslår att man skapar index för saker som referenskoder som egentligen inte behöver indexeras.



  1. Automatiskt inkrementellt datumfält och version oracle sql för en tabell

  2. Anropar SQL Defined funktion i C#

  3. MySQL MAX() funktion för att jämföra numeriska värden i en uppdatering?

  4. Hur gör man en riktig mysqli-förlängningsklass med förberedda uttalanden?