sql >> Base de Datos >  >> RDS >> PostgreSQL

PostgreSQL:¿Cómo indexar todas las claves externas?

EDITAR :Entonces, escribí la consulta a continuación y luego pensé... "espera, Postgresql requiere que los objetivos de clave externa tengan índices únicos". ¿Entonces supongo que entendí mal lo que querías decir? Puede utilizar la siguiente consulta para comprobar que la fuente de sus claves foráneas tienen índices sustituyendo "conrelid" por "confrelid" y "conkey" por "confkey" (sí, sí, no hay alias en la consulta...)

Bueno, supongo que debería ser posible revisar los catálogos del sistema... Como de costumbre, la mejor guía para los catálogos del sistema es usar psql y hacer "\set ECHO_HIDDEN 1" y luego ver qué SQL genera para "\ comandos d". Aquí está el SQL utilizado para encontrar las claves foráneas para una tabla ("\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;

Parece que pg_constraint tiene columnas conkey y confkey que parecen que podrían ser los números de columna en los que se define la clave. Probablemente confkey son los números de columna en la tabla foránea, ya que solo no es nulo para las claves foráneas. Además, me tomó un tiempo darme cuenta de que este es el SQL para mostrar claves foráneas referencia la tabla dada. Que es lo que queremos de todos modos.

Entonces, esta consulta muestra que los datos comienzan a tomar forma:

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

Usaré características de 8.4 como unnest ... es posible que pueda arreglárselas sin él.

Terminé con:

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, ' ')

Bien, esta monstruosidad imprime los comandos de índice candidatos e intenta emparejarlos con los índices existentes. Así que simplemente puede agregar "donde indexrelid es nulo" al final para obtener los comandos para crear índices que no parecen existir.

Esta consulta no trata muy bien con claves foráneas de varias columnas; pero en mi humilde opinión, si los estás usando, te mereces problemas.

EDICIÓN POSTERIOR :aquí está la consulta con las ediciones propuestas en la parte superior. Esto muestra los comandos para crear índices que no existen, en columnas que son el origen de una clave externa (no su destino).

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

Mi experiencia es que esto no es realmente tan útil. Sugiere crear índices para cosas como códigos de referencia que realmente no necesitan ser indexados.