PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL:Jak indeksować wszystkie klucze obce?

EDYTUJ :więc napisałem zapytanie poniżej, a potem pomyślałem... "poczekaj, Postgresql wymaga, aby cele kluczy obcych miały unikalne indeksy." Więc chyba źle zrozumiałem, o co ci chodziło? Możesz użyć poniższego zapytania, aby sprawdzić, czy źródło Twoich kluczy obcych ma indeksy, zastępując „conrelid” za „confrelid” i „conkey” za „confkey” (tak, tak, w zapytaniu nie ma aliasów...)

Cóż, chyba powinno dać się przejrzeć katalogi systemowe... Jak zwykle najlepszym przewodnikiem po katalogach systemowych jest użycie psql i zrobienie "\set ECHO_HIDDEN 1" a potem zobaczenie jaki SQL generuje dla ciekawości "\ d" polecenia. Oto kod SQL używany do znalezienia kluczy obcych dla tabeli ("\d nazwa_tabeli") :

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

Wygląda na to, że pg_constraint ma kolumny conkey i confkey które wyglądają tak, jakby mogły być numerami kolumn, w poprzek których zdefiniowany jest klucz. Prawdopodobnie confkey to numery kolumn w tabeli obcej, ponieważ nie ma wartości null tylko dla kluczy obcych. Zajęło mi też trochę czasu, aby zdać sobie sprawę, że jest to SQL do pokazywania kluczy obcych odwołujących się podanej tabeli. A i tak tego chcemy.

Więc coś, co to zapytanie pokazuje, że dane zaczynają nabierać kształtu:

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

Będę używał funkcji 8.4, takich jak unnest ... możesz się obejść bez.

Skończyło się na:

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, ta potworność drukuje polecenia indeksów kandydujących i próbuje dopasować je do istniejących indeksów. Możesz więc po prostu dodać na końcu „gdzie indexrelid is null”, aby uzyskać polecenia tworzenia indeksów, które wydają się nie istnieć.

To zapytanie nie radzi sobie zbyt dobrze z wielokolumnowymi kluczami obcymi; ale imho, jeśli ich używasz, zasługujesz na kłopoty.

PÓŹNIEJSZE EDYTOWANIE :oto zapytanie z proponowanymi edycjami u góry. To pokazuje polecenia do tworzenia indeksów, które nie istnieją, w kolumnach, które są źródłem klucza obcego (nie jego celem).

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

Z mojego doświadczenia wynika, że ​​to nie jest aż tak przydatne. Sugeruje tworzenie indeksów dla takich rzeczy, jak kody referencyjne, które naprawdę nie muszą być indeksowane.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wykonaj surowe zapytanie podczas migracji - Sequelize 3.30

  2. Pisanie pliku przy użyciu wielu wątków

  3. Jak przełączyć wartość logiczną w postgresie w jednym zapytaniu

  4. Od Now() do Current_timestamp w Postgresql

  5. ECONNREFUSED dla Postgres na nodeJS z dokerami