web-dev-qa-db-fra.com

Créer un index s'il n'existe pas

Je travaille sur une fonction qui me permet d'ajouter un index s'il n'existe pas. Je rencontre le problème que je ne peux pas obtenir une liste d'index à comparer. Des pensées?

Il s'agit d'un problème similaire à celui de la création de colonnes qui est résolu avec ce code:
https://stackoverflow.com/a/12603892/368511

65
GuidoS

Noms d'index dans PostgreSQL

  • Les noms d'index sont uniques sur un schéma de base de données unique.
  • Les noms d'index ne peuvent pas être les mêmes que n'importe quel autre index, table (étrangère), vue (matérialisée), séquence ou type composite défini par l'utilisateur dans le même schéma.
  • Deux tables dans le même schéma ne peuvent pas avoir un index du même nom. (Suit logiquement.)

Si vous ne vous souciez pas du nom de l'index, demandez à Postgres de le nommer automatiquement:

CREATE INDEX ON tbl1 (col1);

est (presque) identique à:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

Sauf que Postgres évitera les collisions de noms et choisira automatiquement le prochain nom gratuit:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Essayez-le. Mais, évidemment, vous ne voudriez pas créer plusieurs index redondants. Il ne serait donc pas judicieux d'en créer un aveuglément.

Test d'existence

Postgres 9.3 ou plus

Un moyen très simple de tester consiste à convertir le nom qualifié du schéma en regclass :

SELECT 'myschema.myname'::regclass;

S'il lève une exception, le nom est libre.
Ou, pour tester le même sans lever d'exception, utilisé dans une instruction 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
$$;

Cela ne fonctionne pas pour CREATE INDEX CONCURRENTLY, Car cette variante ne peut pas être encapsulée dans une transaction externe. Voir commentaire de @Gregory ci-dessous.

L'instruction DO a été introduite avec Postgres 9.0. Dans les versions antérieures, vous devez créer une fonction pour faire de même.
Détails sur pg_class Dans le manuel .
Notions de base sur index dans le manuel .

Postgres 9.4

Vous pouvez utiliser la nouvelle fonction to_regclass() pour vérifier sans lever d'exception:

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

END
$$;

Renvoie NULL si un index (ou un autre objet) de ce nom n'existe pas. Voir:

Postgres 9.5

Maintenant disponible:

CREATE INDEX IF NOT EXISTS ...

Cela fonctionne également pour CREATE INDEX CONCURRENTLY IF NOT EXISTS.

Cependant, le manuel met en garde :

Notez qu'il n'y a aucune garantie que l'index existant ressemble à celui qui aurait été créé.

C'est une simple vérification du nom de l'objet. S'applique à toutes les variantes ici.

105
Erwin Brandstetter
12
Sergey Mirvoda