Створіть індекс, якщо його не існує


60

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

Це схоже питання на створення стовпця, яке вирішено за допомогою цього коду:
https://stackoverflow.com/a/12603892/368511


ви можете спробувати: SELECT * від pg_indexes, де schemaname = '[схема схеми]' та індекс = = [[ім'я індексу] '. Замініть [схему] та [ім'я індексу] належними значеннями. Посилання: 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
...

Просто спробуйте. Але, очевидно, ви б не хотіли створювати кілька зайвих індексів. Тому не було б гарною ідеєю просто сліпо створити нову.

Тест на існування

Постгреси 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в посібнику .
Основи щодо покажчиків у посібнику .

Постгрес 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, якщо індекс (або інший об’єкт) цього імені не існує. Побачити:

Постгрес 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.
gregoltsov

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.