PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL:Wie werden alle Fremdschlüssel indiziert?

BEARBEITEN :Also, ich habe die Abfrage unten geschrieben und dann gedacht ... "Moment mal, Postgresql erfordert, dass Fremdschlüsselziele eindeutige Indizes haben müssen." Also habe ich wohl falsch verstanden, was du meinst? Sie können die folgende Abfrage verwenden, um zu überprüfen, ob die Quelle Ihrer Fremdschlüssel haben Indizes, indem Sie "confrelid" durch "conrelid" und "confkey" durch "conkey" ersetzen (ja, ja, keine Aliase in der Abfrage ...)

Nun, ich schätze, es sollte möglich sein, die Systemkataloge zu durchsuchen ... Wie üblich ist die beste Anleitung zu den Systemkatalogen, psql zu verwenden und "\set ECHO_HIDDEN 1" auszuführen und dann zu sehen, welches SQL es für interessante "\ d" Befehle. Hier ist die SQL, die verwendet wird, um die Fremdschlüssel für eine Tabelle ("\d Tabellenname") zu finden:

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

Scheint, dass pg_constraint Spalten conkey hat und confkey die so aussehen, als könnten sie die Spaltennummern sein, über die der Schlüssel definiert ist. Wahrscheinlich confkey ist die Spaltennummer in der Fremdtabelle, da sie nur für Fremdschlüssel ungleich Null ist. Außerdem brauchte ich eine Weile, um zu erkennen, dass dies die SQL ist, um Fremdschlüssel Referenzen anzuzeigen die angegebene Tabelle. Was wir sowieso wollen.

Diese Abfrage zeigt also, dass die Daten Gestalt annehmen:

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

Ich werde 8.4-Funktionen wie unnest verwenden ... kommen Sie vielleicht auch ohne aus.

Ich endete mit:

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, diese Monstrosität druckt die Kandidatenindexbefehle aus und versucht, sie mit bestehenden Indizes abzugleichen. Sie können also einfach "where indexrelid is null" am Ende hinzufügen, um die Befehle zum Erstellen von Indizes zu erhalten, die scheinbar nicht existieren.

Diese Abfrage geht nicht sehr gut mit mehrspaltigen Fremdschlüsseln um; aber imho, wenn Sie diese verwenden, verdienen Sie Ärger.

SPÄTERE BEARBEITUNG :Hier ist die Abfrage mit den vorgeschlagenen Änderungen ganz oben eingefügt. Dies zeigt also die Befehle zum Erstellen von Indizes, die nicht existieren, für Spalten, die die Quelle eines Fremdschlüssels (nicht sein Ziel) sind.

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

Meine Erfahrung ist, dass das nicht wirklich sinnvoll ist. Es schlägt vor, Indizes für Dinge wie Referenzcodes zu erstellen, die wirklich nicht indiziert werden müssen.