sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL:Hoe indexeer ik alle externe sleutels?

BEWERKEN :dus, ik schreef de onderstaande vraag en dacht toen... "wacht even, Postgresql vereist dat buitenlandse sleuteldoelen unieke indices moeten hebben." Dus ik denk dat ik verkeerd begreep wat je bedoelde? U kunt de onderstaande zoekopdracht gebruiken om te controleren of de bron van uw buitenlandse sleutels hebben indices door "conrelid" te vervangen door "confrelid" en "conkey" door "confkey" (ja, ja, geen aliassen in de zoekopdracht...)

Nou, ik denk dat het mogelijk moet zijn om door de systeemcatalogi te gaan... Zoals gewoonlijk is de beste gids voor de systeemcatalogi om psql te gebruiken en "\set ECHO_HIDDEN 1" te doen en dan te kijken welke SQL het genereert voor interessante "\ d" commando's. Hier is de SQL die wordt gebruikt om de externe sleutels voor een tabel te vinden ("\d tabelnaam"):

-- $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;

Het lijkt erop dat pg_constraint kolommen conkey . heeft en confkey die eruitzien alsof ze de kolomnummers kunnen zijn waarover de sleutel is gedefinieerd. Waarschijnlijk confkey zijn de kolomnummers in de buitenlandse tabel, omdat deze alleen niet-null is voor buitenlandse sleutels. Het kostte me ook een tijdje om te beseffen dat dit de SQL is om externe sleutels te tonen verwijzend de opgegeven tafel. Dat is toch wat we willen.

Dus iets in deze query laat zien dat de gegevens vorm beginnen te krijgen:

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

Ik ga 8.4-functies gebruiken zoals unnest ... je misschien wel zonder kunt.

Ik eindigde met:

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, dit monster drukt de kandidaat-indexopdrachten af ​​en probeert ze te matchen met bestaande indices. U kunt dus eenvoudig "waar indexrelid null is" aan het einde toevoegen om de opdrachten te krijgen om indices te maken die niet lijken te bestaan.

Deze query gaat niet goed om met buitenlandse sleutels met meerdere kolommen; maar als je die gebruikt, verdien je problemen.

LATER BEWERKEN :hier is de zoekopdracht met de voorgestelde bewerkingen bovenaan. Dit toont de opdrachten om indices te maken die niet bestaan, op kolommen die de bron zijn van een externe sleutel (niet het doel ervan).

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

Mijn ervaring is dat dit niet echt handig is. Het stelt voor om indexen te maken voor zaken als referentiecodes die eigenlijk niet geïndexeerd hoeven te worden.



  1. mysql match/tegen

  2. Wijzig de taal van de PostgreSQL-datum van het verzoek

  3. Migreren van MariaDB naar MySQL - verschillen

  4. TransactSQL om een ​​ander TransactSQL-script uit te voeren