Создать индекс, если он не существует

60

Я работаю над функцией, которая позволяет мне добавить индекс, если он не существует. Я столкнулся с проблемой, что я не могу получить список индексов для сравнения. есть идеи?

Эта проблема аналогична проблеме создания столбца, которая решается с помощью следующего кода:
https://stackoverflow.com/a/12603892/368511

Guidos
источник
Вы можете попробовать: SELECT * из pg_indexes, где schemaname = '[schemaname]' и indexname = '[indexname]'. Замените [schemaname] и [indexname] правильными значениями. Ссылка: postgresql.org/docs/9.1/static/view-pg-indexes.html
jbarrameda

Ответы:

102

Индексные имена в PostgreSQL

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

Если вас не интересует имя индекса, попросите Postgres автоматически назвать его:

CREATE INDEX ON tbl1 (col1);

это (почти) так же, как:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

За исключением того, что Postgres избежит конфликтов имен и автоматически выберет следующее свободное имя:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Просто попробуйте. Но, очевидно, вы не захотите создавать несколько избыточных индексов. Так что было бы неплохо просто слепо создать новый.

Тест на существование

Postgres 9.3 или старше

Очень простой способ проверить это привести приведенное к схеме имя к regclass:

SELECT 'myschema.myname'::regclass;

Если выдается исключение, имя является бесплатным.
Или, чтобы проверить то же самое без исключения, используется в DOвыражении:

DO
$$
BEGIN
   IF NOT EXISTS (
      SELECT
      FROM   pg_class c
      JOIN   pg_namespace n ON n.oid = c.relnamespace
      WHERE  c.relname = 'mytable_mycolumn_idx'
      AND    n.nspname = 'myschema'
   ) THEN

        CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
    END IF;
END
$$;

Это не работает CREATE INDEX CONCURRENTLY, так как этот вариант не может быть включен во внешнюю транзакцию. Смотрите комментарий @Gregory ниже.

DOЗаявление было введено с Postgres 9.0. В более ранних версиях вы должны создать функцию, чтобы сделать то же самое.
Подробности pg_classв руководстве .
Основы об указателях в руководстве .

Postgres 9,4

Вы можете использовать новую функцию to_regclass()для проверки без исключения:

DO
$$
BEGIN
   IF to_regclass('myschema.mytable_mycolumn_idx') IS NULL THEN
      CREATE INDEX mytable_mycolumn_idx ON myschema.mytable (mycolumn);
   END IF;

END
$$;

Возвращает NULL, если индекс (или другой объект) с таким именем не существует. Видеть:

Postgres 9,5

Теперь доступно:

CREATE INDEX IF NOT EXISTS ...

Это также работает для CREATE INDEX CONCURRENTLY IF NOT EXISTS.

Тем не менее, руководство предупреждает :

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

Это простая проверка имени объекта. Относится ко всем вариантам здесь.

Эрвин Брандштеттер
источник
7
Будучи хорошим ответом, учтите, что вы не можете добавлять индексы CONCURRENTLYтаким образом. Вы получите ERROR: CREATE INDEX CONCURRENTLY cannot be executed from a function or multi-command string.
Грегольцов