Crie índice se ele não existir

60

Estou trabalhando em uma função que me permite adicionar um índice, se ele não existir. Estou com o problema que não consigo obter uma lista de índices para comparar. Alguma ideia?

Esse é um problema semelhante ao da criação da coluna resolvido com este código:
https://stackoverflow.com/a/12603892/368511

GuidoS
fonte
você pode tentar: SELECT * em pg_indexes em que schemaname = '[schemaname]' e indexname = '[indexname]'. Substitua [schemaname] e [indexname] pelos valores adequados. Ref: postgresql.org/docs/9.1/static/view-pg-indexes.html
jbarrameda

Respostas:

102

Nomes de índice no PostgreSQL

  • Os nomes de índice são exclusivos em um único esquema de banco de dados.
  • Os nomes de índice não podem ser iguais a qualquer outro índice, tabela (estrangeira), exibição (materializada), sequência ou tipo de composto definido pelo usuário no mesmo esquema.
  • Duas tabelas no mesmo esquema não podem ter um índice com o mesmo nome. (Segue logicamente.)

Se você não se importa com o nome do índice, faça com que o Postgres o nomeie automaticamente:

CREATE INDEX ON tbl1 (col1);

é (quase) o mesmo que:

CREATE INDEX tbl1_col1_idx ON tbl1 USING btree (col1);

Exceto que o Postgres evitará colisões de nomes e escolherá automaticamente o próximo nome gratuito:

tbl1_col1_idx 
tbl1_col1_idx2
tbl1_col1_idx3
...

Apenas tente. Mas, obviamente, você não gostaria de criar vários índices redundantes. Portanto, não seria uma boa ideia criar apenas uma nova cegamente.

Teste de existência

Postgres 9.3 ou anterior

Uma maneira muito simples de testar é converter o nome qualificado pelo esquema para regclass:

SELECT 'myschema.myname'::regclass;

Se lançar uma exceção, o nome estará livre.
Ou, para testar o mesmo sem gerar uma exceção, usado em uma DOinstrução:

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

Isso não funciona CREATE INDEX CONCURRENTLY, pois essa variante não pode ser quebrada em uma transação externa. Veja o comentário de @Gregory abaixo.

A DOdeclaração foi introduzida no Postgres 9.0. Nas versões anteriores, você precisa criar uma função para fazer o mesmo.
Detalhes sobre pg_classno manual .
Noções básicas sobre índices no manual .

Postgres 9.4

Você pode usar a nova função to_regclass()para verificar sem gerar uma exceção:

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

END
$$;

Retorna NULL se um índice (ou outro objeto) com esse nome não existir. Vejo:

Postgres 9.5

Agora disponível:

CREATE INDEX IF NOT EXISTS ...

Isso também funciona para CREATE INDEX CONCURRENTLY IF NOT EXISTS.

No entanto, o manual adverte :

Observe que não há garantia de que o índice existente seja semelhante ao que teria sido criado.

É uma verificação simples para o nome do objeto. Aplica-se a todas as variantes aqui.

Erwin Brandstetter
fonte
7
Embora seja uma ótima resposta, observe que você não pode adicionar índices CONCURRENTLYdessa maneira. Você vai conseguir ERROR: CREATE INDEX CONCURRENTLY cannot be executed from a function or multi-command string.
gregoltsov