Manutenção de tabelas: preciso REINDEX uma tabela depois de truncar e repovoar?

5

Eu tenho uma tabela com cerca de 2 milhões de linhas de dados transacionais que usamos para análise. Toda semana nós recarregamos isso com novos dados, então estamos usando TRUNCATE para limpá-lo e depois inserir novas linhas.

Existem alguns índices na tabela. Se eu não derrubar e recriar os índices, precisarei reindexar após cada truncamento e repopulação, ou isso é desnecessário? Devo estar executando VACUUM após TRUNCATE, ou isso também é desnecessário?

    
por JamesF 23.04.2013 / 04:33

1 resposta

3

Não, você geralmente não precisa reindexar depois de TRUNCATE - e, se fizer isso, é muito melhor descartar os índices, carregar os dados e, em seguida, recriar os índices no final.

É um pouco semelhante a esta resposta sobre cluster - O Pg automaticamente descarta o índice durante TRUNCATE e, em seguida, o recria incrementalmente à medida que você insere dados, portanto, não há nenhum excesso de índice retido antes do TRUNCATE .

Você pode obter índices um pouco mais compactos e eficientes se eliminar os índices, truncar, inserir os dados e recriar os índices. Eles certamente serão mais rápidos para construir. A diferença no desempenho do índice, uma vez construída, é improvável que seja suficiente para justificar o esforço extra para a maioria das aplicações usando apenas índices b-tree, mas a diferença no tempo necessário para preencher as tabelas pode valer a pena. Se você estiver usando o GiST ou (especialmente) o GIN, é melhor deixar o índice e recriar no final.

Se for conveniente fazê-lo, elimine os índices e adicione-os novamente no final, mas não se preocupe muito se isso não for prático para você.

Para uma b-tree regular no meu teste, um índice composto criado de forma incremental foi 3720kb contra um índice criado de 2208kb. O tempo de compilação foi de 164 ms (inserções) + 347 ms (índice) versus 742 ms (inserções + índice). Essa diferença é significativa, mas não o suficiente para ser uma grande preocupação, a menos que você esteja fazendo DW em grande escala. Um REINDEX levou mais 342ms após as inserções + execução do índice. Veja

Então, @TomTom está certo (sem surpresas) em que pode valer a pena soltar e recriar índices se for conveniente fazê-lo, como se você estivesse preenchendo tabelas em massa para o trabalho OLAP .

No entanto, a reindexação provavelmente será a resposta errada , já que significa que você faz um monte de trabalho caro para criar um índice e depois descartá-lo. Elimine o índice e recrie-o em vez de reindexar.

Sessão de demonstração:

regress=# -- Create, populate, then create indexes:
regress=# CREATE TABLE demo (someint integer, sometext text);
CREATE TABLE
regress=# \timing on
regress=# INSERT INTO demo (someint, sometext)
SELECT x, (x%100)::text
FROM generate_series(1,100000) x;
INSERT 0 100000
Time: 164.678 ms
regress=# CREATE INDEX composite_idx ON demo(sometext, someint);
CREATE INDEX
Time: 347.958 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 2208 kB
(1 row)
regress=# -- Total time: 347.958+164.678=512.636ms, index size 2208kB

regress=# -- Now, with truncate and insert:
regress=# TRUNCATE TABLE demo;
TRUNCATE TABLE
regress=# INSERT INTO demo (someint, sometext)
SELECT x, (x%100)::text
FROM generate_series(1,100000) x;
INSERT 0 100000
Time: 742.813 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 3720 kB
(1 row)
regress=# -- Total time 742ms, index size 3720kB
regress=# -- Difference: about 44% time increase, about 68% index size increase.
regress=# -- Big-ish, but whether you care depends on your application. Now:

regress=# REINDEX INDEX composite_idx ;
REINDEX
Time: 342.283 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 2208 kB
(1 row)

regress=# -- Index is back to same size, but total time for insert with progressive
regress=# -- index build plus reindex at the end us up to 1084.283, twice as long as
regress=# -- dropping the indexes, inserting the data, and re-creating the indexes took.

Então:

  • Para OLAP, elimine índices, insira, recrie índices.

  • Para o OLTP, você provavelmente só vai querer ficar com construções de índice progressivo. Considere um fator de preenchimento de não-100% nos índices para reduzir os custos de inserção.

  • Evite inserir com compilações progressivas de índice e depois indexe novamente, é o pior dos dois mundos.

É claro que os tamanhos usados neste teste são tamanhos de tabela de brinquedo, então você deve repetir esse teste em uma amostra de seus dados e índices do mundo real para ter uma ideia sólida de quanto diferença faz para você . Repeti esses testes com um fator de escala 100 maior que o anterior e constatei que o índice era quase exatamente o dobro do tamanho se fosse construído de forma incremental, embora a diferença relativa de tempo de construção realmente tenha caído nesse teste em particular.

Então: teste com seus dados e esquema.

    
por 23.04.2013 / 07:54