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

PostgreSQL:Hvordan indekseres alle fremmednøgler?

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.



  1. Ved dublet nøgle ignorere?

  2. Jeg vil have mysql-tabel til at understøtte to sprog

  3. Berørte Oracle JDBC batchUpdate rækker er altid -2 (Statement.SUCCESS_NO_INFO)

  4. Hvad er meningen med SELECT ... FOR XML PATH(' '),1,1)?