Crea indice se non esiste


60

Sto lavorando a una funzione che mi consente di aggiungere un indice se non esiste. Sto incontrando il problema che non riesco a ottenere un elenco di indici con cui confrontare. qualche idea?

Questo è un problema simile a quello della creazione della colonna che è stato risolto con questo codice:
https://stackoverflow.com/a/12603892/368511


puoi provare: SELEZIONA * da pg_indexes dove schemaname = '[schemaname]' e indexname = '[indexname]'. Sostituisci [schemaname] e [indexname] con i valori corretti. Rif: postgresql.org/docs/9.1/static/view-pg-indexes.html
jbarrameda

Risposte:


102

Nomi degli indici in PostgreSQL

  • I nomi degli indici sono univoci in un singolo schema di database.
  • I nomi degli indici non possono essere gli stessi di qualsiasi altro indice, tabella (estranea), vista (materializzata), sequenza o tipo composito definito dall'utente nello stesso schema.
  • Due tabelle nello stesso schema non possono avere un indice con lo stesso nome. (Segue logicamente.)

Se non ti interessa il nome dell'indice, fai in modo che Postgres lo assegni automaticamente:

CREATE INDEX ON tbl1 (col1);

è (quasi) lo stesso di:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

Tranne che Postgres eviterà una collisione di denominazione e sceglierà automaticamente il prossimo nome gratuito:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Provalo e basta. Ma, ovviamente, non vorresti creare più indici ridondanti. Quindi non sarebbe una buona idea crearne uno alla cieca.

Test per l'esistenza

Postgres 9.3 o precedente

Un modo molto semplice per testare è quello di trasmettere il nome qualificato da schema a regclass:

SELECT 'myschema.myname'::regclass;

Se genera un'eccezione, il nome è gratuito.
Oppure, per testare lo stesso senza generare un'eccezione, utilizzato in DOun'istruzione:

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

Questo non funziona CREATE INDEX CONCURRENTLY, dal momento che quella variante non può essere racchiusa in una transazione esterna. Vedi il commento di @Gregory di seguito.

La DOdichiarazione è stata introdotta con Postgres 9.0. Nelle versioni precedenti devi creare una funzione per fare lo stesso.
Dettagli pg_classnel manuale .
Nozioni di base sugli indici nel manuale .

Postgres 9.4

È possibile utilizzare la nuova funzione to_regclass()per verificare senza generare un'eccezione:

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

END
$$;

Restituisce NULL se non esiste un indice (o un altro oggetto) con quel nome. Vedere:

Postgres 9.5

Ora disponibili:

CREATE INDEX IF NOT EXISTS ...

Questo funziona anche per CREATE INDEX CONCURRENTLY IF NOT EXISTS.

Tuttavia, il manuale avverte :

Si noti che non esiste alcuna garanzia che l'indice esistente sia simile a quello che sarebbe stato creato.

È un semplice controllo per il nome dell'oggetto. Si applica a tutte le varianti qui.


7
Pur essendo un'ottima risposta, tieni presente che non puoi aggiungere indici in CONCURRENTLYquesto modo. Otterrai ERROR: CREATE INDEX CONCURRENTLY cannot be executed from a function or multi-command string.
Gregregtsov,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.