quinta-feira, 9 de agosto de 2007

O Comando CREATE INDEX

Este comando cria índices relativos aos dados de uma tabela do PostgreSQL. O bom uso dos índices aumenta bastante o desempenho do acesso a dados, daí a importância do comando.

São objetos que ocupam espaço em disco e podem afetar negativamente o desempenho se mal empregados e em virtude disto devem ser devidamente empregados, gerenciados e mantidos. O comando REINDEX pode ser utilizado para reorganizar os índices mais defasados.

Sintaxe:

CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] name ON table [ USING method ] ( { column | ( expression ) } [ opclass ] [, ...] ) [ WITH ( storage_parameter = value [, ... ] ) ] [ TABLESPACE tablespace ] [ WHERE predicate ]

- UNIQUE - Aceitação ou não de valores repetidos. O padrão é aceitar valores repetidos em um arquivo indexado, mas o uso de UNIQUE gera um erro nesta situação.

- CONCURRENTLY - O uso desta cláusula faz com que não sejam feitos bloqueios à inserção, exclusão e alteração de dados durante a criação do índice. O padrão para a criação de índices é o bloqueio destas operações visando garantir que o índice e seus dados estejam perfeitamente sincronizados, o que pode retardar a criação dos objetos. O comando CREATE INDEX pode ser utilizado em transações apenas se for empregado sem a cláusula CONCURRENTLY.

- Método de indexação - Tipo de índice. Pode ser btree, hash, gist ou gin. O padrão é a árvore B.

- O campo com os valores indexados pode ser na verdade uma expressão calculada utilizando-se uma ou mais colunas da tabela.

- Para cada coluna utilizada no índice deve ser fornecido OPERATOR CLASS, que é o operador a ser utilizado para cada tipo de dado. Normalmente o valor padrão para cada tipo de dado resolve a questão e não se precisa fornecer o OPERATOR CLASS.

- storage_parameter - Atualmente o storage parameter definido para índices é o FILLFACTOR. É uma variável que indica o quanto as folhas da árvore de índice serão utilizadas. Varia de 10 a 100 e seu valor padrão é 90. O valor 100 minimiza o gasto com armazenamento físico do índice, mas pode afetar negativamente o desempenho. O valor 10 privilegia o desempenho, mas requer maior espaço físico para a gravação do índice.

- Cláusula WHERE indicando se o índice é relativo a toda a tabela ou apenas a parte dela (índice parcial).

- Em que tablespace o índice será fisicamente armazenado

Exemplos:

1 – Criação de índice UNIQUE, isto é, sem valores repetidos. Tabela continente, campo nome, nome do índice ind1.

CREATE UNIQUE INDEX ind1 ON continente (nome);

2 – Criação de índice sem UNIQUE, isto é, com valores repetidos e com campo calculado. Ao invés de indexar o campo nome, indexará os valores do campo nome convertidos para minúsculas..

CREATE INDEX ind2 ON continente ((lower(nome)));

3 – Criação de índice UNIQUE com o storage_parameter FILLFACTOR apresentando valor 45.

CREATE UNIQUE INDEX ind3 ON continente (population) WITH (fillfactor = 45);

4 – Criação de índice em determinado tablespace.

CREATE INDEX ind4 ON continente(population) TABLESPACE tspteste;

5 – Criação de índice utilizando a cláusula CONCURRENTLY, com ganho de desempenho.

CREATE INDEX CONCURRENTLY ind5 ON continente (population);

6 – Definição de índice HASH.

CREATE INDEX ind6 ON continente USING hash (nome);

7 – Definição de índice com árvore B.

CREATE UNIQUE INDEX ind7 ON continente USING btree (nome) ;

8 – Definição de índice com UNIQUE e expressão no campo indexado.

CREATE UNIQUE INDEX indexp1 ON continente ((upper(nome)));;

9 – Definição de índice com UNIQUE, BTREE e expressão no campo indexado.

CREATE UNIQUE INDEX indexp2 ON continente USING btree ((cod * 100));

10 – Definição de índice com UNIQUE, BTREE e expressão no campo indexado.

CREATE UNIQUE INDEX indexp3 ON continente USING btree ((cod + tamanho));

11 – Definição de índice parcial, empregando cláusula WHERE em campo numérico.

CREATE UNIQUE INDEX ind9 ON continente (population) WHERE population >10;

12 – Definição de índice parcial, empregando cláusula WHERE em campo alfanumérico.

CREATE UNIQUE INDEX ind10 ON continente (nome) WHERE nome like 'TEC%';

2 comentários:

Telles disse...

Opa, muito bacana esta série sobre índices... este é um assunto que dá pano para manga! Algumas sugestões para explorar mais o tema:

* Seria interessante fazer um EXPLAIN num SELECT de uma grande tabela para comparar o ganho de velocidade e volume em disco de diferentes valores de FILLFACTOR;

* Exemplificar o uso da cláusula CONCURRENTLY;

* Apontar quando a utilização de um determinado índice é melhor (B-TREE, HASH, GIST e GIN);

* Como criar índices que retornem a correta ordenação para pt_BR utilizando o OPERATOR CLASS;

Além disso, seria interessante utilizar uma nomeação para os índices mais consistentes, criar nomes como ind1, ind2 e ind3 não costuma ser muito recomendado.

Fica aí o desafio... o que você acha? Por último deixo aqui a recomendação de uma apresentação interesante do Sr. Josh Berkus chamada The Joy Of Index que é bem interessante.

[]s

Marcos G.A disse...

Interessante este material, ainda que se passado muitos anos, é uma fonte de pesquisa e aprendizagem bem interessante.