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


60

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

Ceci est un problème similaire à celui de la création de colonne qui est résolu avec ce code:
https://stackoverflow.com/a/12603892/368511


vous pouvez essayer: SELECT * from pg_indexes où schemaname = '[schemaname]' et indexname = '[indexname]'. Remplacez [schemaname] et [indexname] par les valeurs appropriées. Réf: postgresql.org/docs/9.1/static/view-pg-indexes.html
jbarrameda

Réponses:


102

Noms d'index dans PostgreSQL

  • Les noms d'index sont uniques dans un schéma de base de données unique.
  • Les noms d'index ne peuvent pas être identiques à tout 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 conflits de noms et choisira automatiquement le nom suivant libre:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Juste l'essayer. Mais, évidemment, vous ne voudriez pas créer plusieurs index redondants. Donc, ce ne serait pas une bonne idée de créer aveuglément un nouveau.

Test d'existence

Postgres 9.3 ou plus ancien

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 une exception, utilisé dans une DOdéclaration:

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 CREATE INDEX CONCURRENTLYcar cette variante ne peut pas être encapsulée dans une transaction externe. Voir le commentaire de @Gregory ci-dessous.

La DOdéclaration 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_classdans le manuel .
Notions de base sur les 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) portant ce nom n'existe pas. Voir:

Postgres 9.5

Maintenant disponible:

CREATE INDEX IF NOT EXISTS ...

Cela fonctionne aussi 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 un contrôle simple du nom de l'objet. S'applique à toutes les variantes ici.


7
Tout en étant une excellente réponse, notez que vous ne pouvez pas ajouter d’index de CONCURRENTLYcette façon. Vous aurez ERROR: CREATE INDEX CONCURRENTLY cannot be executed from a function or multi-command string.
gregoltsov

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.