PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

PostgreSQL :Comment indexer toutes les clés étrangères ?

MODIFIER :donc, j'ai écrit la requête ci-dessous et j'ai ensuite pensé ... "attendez, Postgresql exige que les cibles de clé étrangère aient des index uniques." Donc je suppose que j'ai mal compris ce que tu voulais dire ? Vous pouvez utiliser la requête ci-dessous pour vérifier que la source de vos clés étrangères ont des indices en substituant "conrelid" à "confrelid" et "conkey" à "confkey" (ouais, ouais, pas d'alias dans la requête...)

Eh bien, je suppose qu'il devrait être possible de parcourir les catalogues système ... Comme d'habitude, le meilleur guide pour les catalogues système est d'utiliser psql et de faire "\set ECHO_HIDDEN 1" puis de voir quel SQL il génère pour intéressant "\ d". Voici le SQL utilisé pour trouver les clés étrangères d'une table ("\d tablename") :

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

Il semble que pg_constraint ait des colonnes conkey et confkey qui semblent être les numéros de colonne dans lesquels la clé est définie. Probablement confkey est le numéro de colonne dans la table étrangère puisqu'il n'est non nul que pour les clés étrangères. De plus, j'ai mis un certain temps à réaliser que c'est le SQL pour afficher les clés étrangères référençant le tableau donné. C'est ce que nous voulons de toute façon.

Donc quelque chose que cette requête montre que les données commencent à prendre forme :

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

Je vais utiliser des fonctionnalités 8.4 comme unnest ... vous pourriez peut-être vous en passer.

J'ai fini par :

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, cette monstruosité imprime les commandes d'indexation candidates et essaie de les faire correspondre avec les index existants. Vous pouvez donc simplement ajouter "où indexrelid est nul" à la fin pour obtenir les commandes permettant de créer des index qui ne semblent pas exister.

Cette requête ne gère pas très bien les clés étrangères multi-colonnes; mais à mon humble avis, si vous les utilisez, vous méritez des ennuis.

MODIFICATION ULTÉRIEURE  :voici la requête avec les modifications proposées en haut. Cela montre donc les commandes pour créer des index qui n'existent pas, sur des colonnes qui sont la source d'une clé étrangère (pas sa cible).

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

Mon expérience est que ce n'est pas vraiment utile. Il suggère de créer des index pour des choses comme les codes de référence qui n'ont vraiment pas besoin d'être indexés.