Crear índice si no existe


60

Estoy trabajando en una función que me permite agregar un índice si no existe. Me encuentro con el problema que no puedo obtener una lista de índices para comparar. ¿Alguna idea?

Este es un problema similar al de creación de columnas que se resuelve con este código:
https://stackoverflow.com/a/12603892/368511


puede intentar: SELECCIONAR * de pg_indexes donde schemaname = '[schemaname]' e indexname = '[indexname]'. Reemplace [schemaname] y [indexname] con los valores adecuados. Ref: postgresql.org/docs/9.1/static/view-pg-indexes.html
jbarrameda

Respuestas:


102

Indice de nombres en PostgreSQL

  • Los nombres de índice son únicos en un único esquema de base de datos.
  • Los nombres de índice no pueden ser los mismos que cualquier otro índice, tabla (extranjera), vista (materializada), secuencia o tipo compuesto definido por el usuario en el mismo esquema.
  • Dos tablas en el mismo esquema no pueden tener un índice del mismo nombre. (Sigue lógicamente)

Si no le importa el nombre del índice, haga que Postgres lo nombre automáticamente:

CREATE INDEX ON tbl1 (col1);

es (casi) lo mismo que:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

Excepto que Postgres evitará una colisión de nombres y elegirá automáticamente el siguiente nombre gratis:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Solo inténtalo. Pero, obviamente, no querrá crear múltiples índices redundantes. Por lo tanto, no sería una buena idea crear a ciegas uno nuevo.

Prueba de existencia

Postgres 9.3 o anterior

Una forma muy simple de probar es emitir el nombre calificado para el esquema a regclass:

SELECT 'myschema.myname'::regclass;

Si arroja una excepción, el nombre es gratis.
O, para probar lo mismo sin lanzar una excepción, usado en una DOdeclaración:

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
$$;

Esto no funciona CREATE INDEX CONCURRENTLY, ya que esa variante no se puede incluir en una transacción externa. Ver comentario de @Gregory a continuación.

La DOdeclaración se introdujo con Postgres 9.0. En versiones anteriores, debe crear una función para hacer lo mismo.
Detalles sobre pg_classen el manual .
Conceptos básicos sobre los índices en el manual .

Postgres 9.4

Puede usar la nueva función to_regclass()para verificar sin lanzar una excepción:

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

END
$$;

Devuelve NULL si no existe un índice (u otro objeto) de ese nombre. Ver:

Postgres 9.5

Ya disponible:

CREATE INDEX IF NOT EXISTS ...

Eso también funciona para CREATE INDEX CONCURRENTLY IF NOT EXISTS.

Sin embargo, el manual advierte :

Tenga en cuenta que no hay garantía de que el índice existente sea similar al que se habría creado.

Es una simple verificación del nombre del objeto. Se aplica a todas las variantes aquí.


77
Si bien es una gran respuesta, tenga en cuenta que no puede agregar índices de CONCURRENTLYesta manera. Lo conseguirás ERROR: CREATE INDEX CONCURRENTLY cannot be executed from a function or multi-command string.
gregoltsov

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.