REINDEX

REINDEX — reconstrói índices

Sinopse

REINDEX [ ( opção [, ...] ) ]
    { INDEX | TABLE | SCHEMA } [ CONCURRENTLY ] nome
REINDEX [ ( opção [, ...] ) ]
    { DATABASE | SYSTEM } [ CONCURRENTLY ] [ nome ]

onde opção pode ser uma entre:

    CONCURRENTLY [ booleano ]
    TABLESPACE novo_espaço_de_tabelas
    VERBOSE [ booleano ]

Descrição

O comando REINDEX reconstrói o índice usando os dados armazenados na tabela do índice, substituindo a cópia antiga do índice. Existem vários cenários nos quais usar REINDEX:

  • O índice está corrompido, não contendo mais dados válidos. Embora em teoria isto nunca deva acontecer, na prática, os índices podem ser corrompidos devido a bugs de software ou falhas de hardware. O comando REINDEX fornece um método de recuperação.

  • O índice tornou-se inchado, ou seja, contém muitas páginas vazias, ou quase vazias. Isto pode ocorrer com índices Árvore-B no PostgreSQL sob certos padrões de acesso incomuns. O comando REINDEX fornece uma maneira de reduzir o consumo de espaço do índice escrevendo uma nova versão do índice sem as páginas mortas. Veja Reindexação de rotina para obter mais informações.

  • Se foi alterado um parâmetro de armazenamento (como o fator de preenchimento) para o índice, e se deseja garantir que a alteração tenha efeito total.

  • Se a construção de um índice falhar com a opção CONCURRENTLY, este índice será deixado como inválido. Estes índices são inúteis, mas pode ser conveniente usar REINDEX para reconstruí-los. Note que apenas REINDEX INDEX pode executar a construção concorrente de um índice inválido.

Parâmetros

INDEX

Recria o índice especificado. Esta forma de REINDEX não pode ser executada dentro de um bloco de transação, quando usada com um índice particionado.

TABLE

Recria todos os índices da tabela especificada. Se a tabela tiver uma tabela TOAST secundária, ela também será reindexada. Esta forma de REINDEX não pode ser executada dentro de um bloco de transação, quando usada com uma tabela particionada.

SCHEMA

Recria todos os índices do esquema especificado. Se uma tabela desse esquema tiver uma tabela TOAST secundária, ela também será reindexada. Índices em catálogos do sistema compartilhados também são processados. Esta forma de REINDEX não pode ser executada dentro de um bloco de transação.

DATABASE

Recria todos os índices no banco de dados corrente, exceto os catálogos do sistema. Os índices dos catálogos do sistema não são processados. Esta forma do comando REINDEX não pode ser executada dentro de um bloco de transação.

SYSTEM

Recria todos os índices nos catálogos do sistema no banco de dados corrente. Os índices em catálogos do sistema compartilhados são incluídos. Os índices em tabelas do usuário não são processados. Esta forma do comando REINDEX não pode ser executada dentro de um bloco de transação.

nome

O nome do índice, tabela ou banco de dados específico a ser reindexado. Os nomes de índices e tabelas podem ser qualificados pelo esquema. No momento, REINDEX DATABASE e REINDEX SYSTEM só podem reindexar o banco de dados corrente, sendo o parâmetro opcional, devendo corresponder ao nome do banco de dados corrente.

CONCURRENTLY

Quando esta opção é usada, o PostgreSQL irá reconstruir o índice sem obter nenhum bloqueio que impeça inserções, atualizações ou exclusões simultâneas na tabela; enquanto uma reconstrução de índice padrão bloqueia as escritas (mas não as leituras) na tabela até que termine. Há várias advertências a serem observadas ao usar esta opção — veja Reconstrução concorrente de índices abaixo.

Para tabelas temporárias, o comando REINDEX é sempre não concorrente, porque nenhuma outra sessão pode acessá-las, e a reindexação não concorrente é mais econômica.

TABLESPACE

Especifica que os índices serão reconstruídos em um novo espaço de tabelas.

VERBOSE

Gera um relatório de progresso no nível INFO enquanto cada índice é reindexado.

booleano

Especifica se a opção selecionada deve ser ativada ou desativada. Pode ser escrito TRUE, ON, ou 1 para ativar a opção, e FALSE, OFF, ou 0 para desativá-la. O valor booleano também pode ser omitido, caso em que é assumido o valor TRUE.

novo_espaço_de_tabelas

O espaço de tabelas onde os índices serão reconstruídos.

Notas

Havendo suspeita de corrupção de um índice em uma tabela de usuário, pode-se simplesmente reconstruir este índice, ou todos os índices da tabela, usando os comandos REINDEX INDEX, ou REINDEX TABLE.

As coisas são mais difíceis quando é necessário se recuperar da corrupção de um índice em uma tabela do sistema. Neste caso, é importante que o próprio sistema não tenha utilizado nenhum dos índices suspeitos. (De fato, neste tipo de cenário, pode-se descobrir que os processos do servidor estão travando imediatamente na inicialização, devido à dependência de índices corrompidos.) Para recuperar com segurança, o servidor deve ser iniciado com a opção -P, que impede o uso de índices para procuras nos catálogos do sistema.

Uma maneira de fazer isto é parar o servidor, e iniciar o servidor PostgreSQL de usuário único com a opção -P incluída na linha de comando. Então, pode ser executado REINDEX DATABASE, REINDEX SYSTEM, REINDEX TABLE, ou REINDEX INDEX, dependendo de quanto se deseja reconstruir. Em caso de dúvida, deve ser usado REINDEX SYSTEM para selecionar a reconstrução de todos os índices do sistema no banco de dados. Em seguida, sair da sessão de servidor de usuário único, e reiniciar o servidor normalmente. Veja a página de referência do postgres para obter mais informações sobre como interagir com a interface de servidor de usuário único.

Como alternativa, pode ser iniciada uma sessão normal do servidor com a opção -P incluída em suas opções de linha de comando. O método para fazer isto varia entre clientes, mas em todos os clientes baseados na libpq é possível definir a variável de ambiente PGOPTIONS como -P antes de iniciar o cliente. Note que, embora este método não exija o bloqueio de outros clientes, ainda pode ser prudente impedir que outros usuários conectem ao banco de dados danificado até que os reparos sejam concluídos.

O comando REINDEX é semelhante a excluir e recriar o índice, onde o conteúdo do índice é reconstruído a partir do zero. Entretanto, as considerações de bloqueio são bastante diferentes. O comando REINDEX bloqueia escritas, mas não leituras da tabela associada do índice. Ele também requer um bloqueio ACCESS EXCLUSIVE no índice específico que está sendo processado, o que irá bloquear as leituras que tentarem usar este índice. Em particular, o planejador de consultas tenta obter um bloqueio ACCESS SHARE em todos os índices da tabela, independentemente da consulta e, portanto, o comando REINDEX bloqueia praticamente todas as consultas, exceto algumas consultas preparadas cujo plano foi armazenado em cache e que não usam este índice específico. Em contraste, o comando DROP INDEX obtém momentaneamente um bloqueio ACCESS EXCLUSIVE na tabela associada, bloqueando escritas e leituras. O comando CREATE INDEX subsequente bloqueia as escritas, mas não as leituras; como o índice ainda não existe, nenhuma leitura tentará usá-lo, significando que não haverá bloqueio, mas as leituras podem ser forçadas a realizar varreduras sequenciais dispendiosas.

Enquanto o comando REINDEX estiver em execução, o search_path será temporariamente mudado para pg_catalog, pg_temp.

A reindexação de um único índice ou tabela requer o privilégio MAINTAIN na tabela. Note que o comando REINDEX em um índice ou tabela particionada requer o privilégio MAINTAIN na tabela particionada, ignorando as verificações de privilégios ao processar as partições individuais. Reindexar um esquema ou banco de dados requer ser o dono desse esquema ou banco de dados, ou ter privilégios de função de banco de dados pg_maintain. Note especificamente que, dessa forma, é possível que usuários sem privilégios de superusuário reconstruam índices de tabelas pertencentes a outros usuários. Entretanto, como uma exceção especial, REINDEX DATABASE, REINDEX SCHEMA, e REINDEX SYSTEM irão pular os índices nos catálogos compartilhados, a menos que o usuário tenha o privilégio MAINTAIN no catálogo.

A reindexação de índices particionados, ou tabelas particionadas, tem suporte com REINDEX INDEX ou REINDEX TABLE, respectivamente. Cada partição da relação particionada especificada é reindexada em uma transação separada. Estes comandos não podem ser usados dentro de um bloco de transação ao trabalhar em uma tabela ou índice particionado.

Ao usar a cláusula TABLESPACE com o comando REINDEX em um índice ou tabela particionada, apenas as referências a espaço de tabelas das partições folha são atualizadas. Como os índices particionados não são atualizados, se recomenda usar neles ALTER TABLE ONLY em separado, para que quaisquer novas partições anexadas herdem o novo espaço de tabelas. Em caso de falha, pode não ter sido movido todos os índices para o novo espaço de tabelas. Executar novamente o comando reconstruirá todas as partições folha e moverá os índices não processados anteriormente para o novo espaço de tabelas.

Se for usado SCHEMA, DATABASE ou SYSTEM com TABLESPACE, as relações do sistema serão ignoradas, e será gerado um único WARNING. Os índices nas tabelas TOAST são reconstruídos, mas não são movidos para o novo espaço de tabelas.

Reconstrução concorrente de índices

A reconstrução de um índice pode interferir na operação regular do banco de dados. Normalmente, o PostgreSQL bloqueia contra escritas a tabela cujo índice é reconstruído, e executa a construção inteira do índice em uma única varredura da tabela. As demais transações ainda podem ler a tabela, mas se tentarem inserir, atualizar ou excluir linhas na tabela, elas serão bloqueadas até que a reconstrução do índice esteja concluída. Isto pode provocar um impacto importante, se o sistema for um banco de dados de produção ativo. Tabelas muito grandes podem levar muitas horas para serem indexadas e, mesmo em tabelas menores, a reconstrução do índice pode bloquear escrever por períodos inaceitavelmente longos para um sistema em produção.

O PostgreSQL oferece suporte à reconstrução de índices com bloqueio mínimo de escrita. Este método é chamado especificando a opção CONCURRENTLY no comando REINDEX. Quando esta opção é usada, o PostgreSQL deve executar duas varreduras da tabela para cada índice que precisa ser reconstruído, e aguardar o término de todas as transações existentes que poderiam potencialmente usar o índice. Este método requer mais trabalho total do que a reconstrução de índice padrão, levando muito mais tempo para ser concluído, porque precisa aguardar pelas transações não concluídas que podem modificar o índice. Entretanto, como permite que as operações normais prossigam enquanto o índice está sendo reconstruído, este método é útil para a reconstrução de índices em um ambiente de produção. Obviamente, a carga extra de CPU e E/S imposta pela recriação do índice pode retardar outras operações.

As etapas a seguir ocorrem em uma reindexação concorrente. Cada etapa é executada em uma transação separada. Havendo vários índices a serem reconstruídos, cada etapa percorrerá todos os índices antes de passar para a próxima etapa.

  1. Uma nova definição de índice transitória é adicionada ao catálogo pg_index. Esta definição será usada para substituir a antiga definição do índice. É obtido o bloqueio SHARE UPDATE EXCLUSIVE no nível da sessão nos índices que estão sendo reindexados, bem como em suas tabelas associadas, para evitar qualquer modificação de esquema durante o processamento.

  2. É realizada uma primeira passagem para construir o índice para cada novo índice. Após o índice ser construído, seu sinalizador pg_index.indisready é alterado para true, para torná-lo pronto para inserções, tornando-o visível para as outras sessões assim que a transação que executou a construção esteja finalizada. Esta etapa é realizada em uma transação separada para cada índice.

  3. Em seguida, uma segunda passagem é executada para adicionar as tuplas que foram adicionadas durante a execução da primeira passagem. Esta etapa também é realizada em uma transação separada para cada índice.

  4. Todas as restrições que se referem ao índice são alteradas para se referir à nova definição do índice, e os nomes dos índices são alterados. Neste ponto, pg_index.indisvalid é alterado para true para o novo índice, e para false para o antigo, e uma invalidação de cache é feita, fazendo com que todas as sessões que faziam referência ao índice antigo sejam invalidadas.

  5. Os índices antigos têm pg_index.indisready mudado para false, para evitar novas inserções de tuplas, após aguardar a execução das consultas que possam fazer referência ao índice antigo serem concluídas.

  6. Os índices antigos são removidos. Os bloqueios de sessão SHARE UPDATE EXCLUSIVE para os índices e a tabela são liberados.

Se ocorrer um problema durante a reconstrução dos índices, como uma violação de unicidade em um índice de unicidade, o comando REINDEX irá falhar, mas deixará para trás um novo índice inválido, além do anterior pré-existente. Este índice será ignorado para fins de consulta, porque pode estar incompleto; entretanto, ainda consumirá sobrecarga de atualização. O meta-comando \d do psql irá mostrar este índice como INVALID:

postgres=# \d tab
       Table "public.tab"
 Column |  Type   | Modifiers
--------+---------+-----------
 col    | integer |
Indexes:
    "idx" btree (col)
    "idx_ccnew" btree (col) INVALID

Se o índice marcado como INVALID tiver o sufixo _ccnew, então corresponde ao índice transitório criado durante a operação concorrente, e o método de recuperação recomendado é removê-lo usando DROP INDEX, e depois tentado REINDEX CONCURRENTLY novamente. Se o índice inválido tiver o sufixo _ccold, ele corresponde ao índice original que não pôde ser removido; o método de recuperação recomendado é apenas remover o referido índice, porque a reconstrução adequada foi bem-sucedida. Pode ser adicionado um número diferente de zero ao sufixo dos nomes de índice inválidos para mantê-los únicos, como por exemplo _ccnew1, _ccold2, etc.

As construções de índices regulares permitem que ocorram outras construções de índices regulares na mesma tabela ao mesmo tempo, mas só pode haver uma construção de índice concorrente em uma tabela por vez. Nos dois casos, nenhum outro tipo de modificação do esquema da tabela é permitido enquanto o índice está sendo construído. Outra diferença, é que um comando REINDEX TABLE ou REINDEX INDEX regular pode ser executado dentro de um bloco de transação, mas REINDEX CONCURRENTLY não pode.

Como qualquer transação de longa duração, o comando REINDEX de uma tabela pode afetar as tuplas que podem ser removidas pelo comando VACUUM simultâneo em qualquer outra tabela.

O comando REINDEX SYSTEM não oferece suporte à cláusula CONCURRENTLY, já que os catálogos do sistema não podem ser reindexados de forma concorrente.

Além disso, os índices para restrições de exclusão não podem ser reindexados de forma concorrente. Se tal índice for especificado diretamente neste comando, será relatado erro. Se uma tabela ou banco de dados com índices de restrição de exclusão for reindexado de forma concorrente, estes índices serão ignorados. (É possível reindexar estes índices sem a opção CONCURRENTLY.)

Cada processo servidor executando REINDEX relata seu progresso na visão pg_stat_progress_create_index. Veja Relatório de progresso do CREATE INDEX para obter detalhes.

Exemplos

Reconstruir um único índice:

REINDEX INDEX my_index;

Reconstruir todos os índices na tabela my_table:

REINDEX TABLE my_table;

Reconstruir todos os índices em um banco de dados específico, sem confiar que os índices do sistema já estejam válidos:

$ export PGOPTIONS="-P"
$ psql broken_db
...
broken_db=> REINDEX DATABASE broken_db;
broken_db=> \q

Reconstruir índices para uma tabela, sem bloquear as operações de leitura e escrita nas relações envolvidas enquanto a reindexação está em andamento:

REINDEX TABLE CONCURRENTLY my_broken_table;

Conformidade

Não existe o comando REINDEX no padrão SQL.

Veja também

CREATE INDEX, DROP INDEX, reindexdb, Relatório de progresso do CREATE INDEX