PostgreSQL: Как индексировать все внешние ключи?

Я работаю с большой базой данных PostgreSQL, и я пытаюсь настроить ее для получения большего количества производительности.

Наши запросы и обновления, кажется, делают много поисков с помощью внешних ключей.

То, что я хотел бы, является относительно простым способом добавить Индексы ко всем нашим внешним ключам, не имея необходимость проходить каждую таблицу (~140) и делая его вручную.

В исследовании этого я приехал, чтобы найти, что нет никакого способа сделать, чтобы Пост-ГРЭС сделала это для Вас автоматически (как MySQL, делает), но я был бы рад услышать иначе там, также.

15
задан biggusjimmus 4 June 2010 в 17:28
поделиться

2 ответа

РЕДАКТИРОВАТЬ : итак, я написал запрос ниже и подумал ... «Постойте, Postgresql требует, чтобы цели внешнего ключа имели уникальные индексы». Думаю, я неправильно понял, что вы имели в виду? Вы можете использовать приведенный ниже запрос, чтобы проверить, что источник ваших внешних ключей имеет индексы, заменив «conrelid» на «confrelid» и «conkey» на «confkey» (да, да, в запросе нет псевдонимов ...)

Что ж, я думаю, что должна быть возможность просматривать системные каталоги ... Как обычно, лучший справочник по системным каталогам - это использовать psql и выполнить "\ set ECHO_HIDDEN 1", а затем посмотреть, что SQL он генерирует для интересных команд "\ d". Вот SQL, используемый для поиска внешних ключей для таблицы ("\ 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;

Похоже, что pg_constraint имеет столбцы conkey и confkey , которые выглядят так, как будто они могут быть номера столбцов, в которых определяется ключ. Вероятно, confkey - это номера столбцов во внешней таблице, поскольку они не равны NULL только для внешних ключей. Кроме того, мне потребовалось время, чтобы понять, что это SQL, чтобы показать внешние ключи , ссылающиеся на данную таблицу. В любом случае это то, чего мы хотим.

Таким образом, этот запрос показывает, что данные начинают обретать форму:

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

Я собираюсь использовать функции 8.4, такие как unnest ... вы могли бы обойтись и без них.

В итоге я получил:

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

Хорошо, это чудовище распечатывает команды кандидатов-индексов и пытается сопоставить их с существующими индексами. Таким образом, вы можете просто добавить в конце «where indexrelid is null», чтобы получить команды для создания индексов, которые кажутся несуществующими.

Этот запрос не очень хорошо работает с внешними ключами с несколькими столбцами; но имхо, если вы их используете, вы заслуживаете неприятностей.

LATER EDIT : вот запрос с предложенными изменениями вверху, вставленными. Итак, здесь показаны команды для создания индексов, которые не существуют, для столбцов, которые являются источником внешнего ключа (не его цель).

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

По моему опыту, это не так уж и полезно. Он предлагает создавать индексы для таких вещей, как ссылочные коды, которые действительно не нужно индексировать.

18
ответ дан 1 December 2019 в 03:04
поделиться

Информация находится в таблицах каталога. Но, похоже, это не очень просто сделать то, что вам нужно, особенно если уже созданы некоторые индексы (а как насчет многоколоночных индексов...)

Если у вас нет индексированных FK, вы можете сделать что-то быстрое и грязное, как

 SELECT 'CREATE INDEX ' || table_name || '_' || column_name || '_idx ON '
   || table_name || '(' || column_name || ');'
from foreign_key_tables where schema = 'public';

Вы замените схему, которая вас интересует, сбросите ее в файл, отредактируйте, проверьте, помолитесь и скормите psql. ОСТОРОЖНО, эта процедура не обнаруживает уже существующие индексы.

А, foreign_key_tables - это информационное представление, созданное как:

CREATE VIEW foreign_key_tables AS SELECT
    n.nspname AS schema,
    cl.relname AS table_name,
    a.attname AS column_name,
    ct.conname AS key_name,
    nf.nspname AS foreign_schema,
    clf.relname AS foreign_table_name,
    af.attname AS foreign_column_name,
    pg_get_constraintdef(ct.oid) AS create_sql
FROM pg_catalog.pg_attribute a
JOIN pg_catalog.pg_class cl ON (a.attrelid = cl.oid AND cl.relkind =
'r')
JOIN pg_catalog.pg_namespace n ON (n.oid = cl.relnamespace)
JOIN pg_catalog.pg_constraint ct ON (a.attrelid = ct.conrelid AND
ct.confrelid != 0 AND ct.conkey[1] = a.attnum)
JOIN pg_catalog.pg_class clf ON (ct.confrelid = clf.oid AND clf.relkind
= 'r')
JOIN pg_catalog.pg_namespace nf ON (nf.oid = clf.relnamespace)
JOIN pg_catalog.pg_attribute af ON (af.attrelid = ct.confrelid AND
af.attnum = ct.confkey[1]);
6
ответ дан 1 December 2019 в 03:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: