Recentemente, tive um servidor PostgreSQL 8.2.11 atualizado para 8.4, a fim de tirar proveito dos recursos de autovacuum e estar alinhado com outros 30 servidores PGSQL. Isso foi feito por um grupo de TI separado que administra o hardware, para que não tenhamos muitas opções em outras atualizações (não haverá mais de 9 anos por um tempo). O servidor existe em um ambiente muito fechado (rede isolada, privilégios de root limitados) e é executado no RHEL5.5 (i686). Após a atualização, o banco de dados aumentou constantemente para 5-6 GB por dia. Normalmente, o banco de dados, como um todo, tem ~ 20 GB; atualmente, é ~ 89GB. Temos outros servidores que executam bancos de dados equivalentes e, na verdade, sincronizam os registros entre si por meio de um aplicativo de terceiros (um que eu não tenho acesso ao funcionamento interno). Os outros bancos de dados têm aproximadamente 20 GB como deveriam.
Executando o SQL a seguir, é bastante óbvio que há um problema com uma tabela específica e, mais especificamente, sua tabela TOAST.
SELECT nspname || '.' || relname AS "relation",
pg_size_pretty(pg_relation_size(C.oid)) AS "size"
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY pg_relation_size(C.oid) DESC
LIMIT 20;
Qual produz:
relação | Tamanho ------------------------------------ + --------- pg_toast.pg_toast_16874 | 89 GB fews00.warmstates | 1095 MB ... (20 linhas)
Esta tabela TOAST é para uma tabela chamada "timeseries" que salva grandes registros de dados em blob. Um SUM(LENGTH(blob)/1024./1024.)
de todos os registros nas séries temporais gera ~ 16 GB para essa coluna. Não deve haver razão para a tabela TOAST dessa tabela ser tão grande quanto é.
Eu executei um VACUUM FULL VERBOSE ANALYZE timeseries
e o vácuo é executado sem erros.
INFO: limpando "pg_toast.pg_toast_16874"
INFO: "pg_toast_16874": encontrado 22483 removível, 10475318 versões de linhas não removíveis em 10448587 páginas
DETALHE: 0 versões de linhas inativas ainda não podem ser removidas.
As versões de linhas não removíveis variam de 37 a 2036 bytes.
Havia 20121422 ponteiros de itens não utilizados.
O espaço livre total (incluindo versões de linhas removíveis) é 0 bytes. As páginas 4944885 estão ou ficarão vazias, incluindo 0 no final da tabela. 4944885 páginas contendo 0 bytes livres são possíveis destinos de movimentação.
CPU 75.31s / 29.59u s decorridos 877.79 s.
INFO: o índice "pg_toast_16874_index" agora contém 10475318 versões de linha em 179931 páginas
DETALHE: 23884 versões de linha de índice foram removidas.
101623 páginas de índice foram excluídas, 101623 são atualmente reutilizáveis.
CPU 1.35s / 2.46u seg decorridos 21.07 seg.
REINDEXED a tabela que liberou algum espaço (~ 1 GB). Não consigo CLUSTER a tabela, pois não há espaço suficiente no disco para o processo, e estou esperando para reconstruir a tabela completamente, pois gostaria de descobrir por que ela é muito maior do que os bancos de dados equivalentes que temos.
Fiz uma consulta no wiki do PostgreSQL aqui - "Show Database Bloat" , e é isso que eu recebo:
banco de dados atual | schemaname | tablename | tbloat | wastedbytes | iname | ibloat wastedibytes ----------------- + ------------ + ------------------- ------------- + -------- + ------------- + ------------- -------------------- + -------- + -------------- ptrdb04 fews00 | séries temporais | 1.0 0 idx_timeseries_synchlevel | 0,0 | 0 0 ptrdb04 fews00 | séries temporais | 1.0 0 idx_timeseries_localavail | 0,0 | 0 0 ptrdb04 fews00 | séries temporais | 1.0 0 idx_timeseries_expirytime | 0,0 | 0 0 ptrdb04 fews00 | séries temporais | 1.0 0 idx_timeseries_expiry_null | 0,0 | 0 0 ptrdb04 fews00 | séries temporais | 1.0 0 uniq_localintid | 0,0 | 0 0 ptrdb04 fews00 | séries temporais | 1.0 0 pk_timeseries | 0,1 0 0 ptrdb04 fews00 | idx_timeseries_expiry_null | 0,6 | 0 ? | 0,0 | 0 0
Parece que o banco de dados não considera esse espaço como "vazio", mas não vejo de onde vem todo o espaço em disco!
Suspeito que este servidor de banco de dados esteja decidindo usar 4-5x tanto espaço em disco para salvar os mesmos registros extraídos dos outros servidores de dados. Minha pergunta é a seguinte: Existe uma maneira de verificar o tamanho do disco físico de uma linha? Eu gostaria de comparar o tamanho de uma linha nesse banco de dados com outro banco de dados "íntegro".
Obrigado por qualquer ajuda que você pode fornecer!
ATUALIZAÇÃO 1
Acabei reconstruindo a tabela a partir de um esquema despejado devido ao seu tamanho (não foi possível deixá-la sozinha por mais um dia). Após a sincronização dos dados, através do processo de sincronização do software, a tabela TOAST foi de ~ 35 GB; no entanto, eu poderia contabilizar apenas ~ 9 GB dessa coluna de blob, que deve ser a mais longa em termos de valores. Não sei de onde vêm os outros 26 GB. CLUSTERed, VACUUM CHEIO e REINDEXed sem sucesso. Os arquivos postgresql.conf entre os servidores de dados local e remoto são exatamente os mesmos. Existe alguma razão para esse banco de dados estar tentando armazenar cada registro com um espaço maior no disco?
ATUALIZAÇÃO 2 - Fixa
Finalmente, decidi reconstruir completamente o banco de dados desde o início - até reinstalar os pacotes do PostgreSQL84 no sistema. O caminho do banco de dados foi reinicializado e os espaços de tabela limpos. O processo de sincronização de software de terceiros repovoou as tabelas e o tamanho final ficou em ~ 12 GB ! Infelizmente, isso não ajuda em nada a resolver qual era a fonte exata do problema. Vou assistir por um dia ou dois e ver se há grandes diferenças em como o banco de dados revitalizado está lidando com a tabela TOAST e postar esses resultados aqui.
Tamanho da relação
ptrdb04=> SELECT nspname || '.' || relname AS "relation",
ptrdb04-> pg_size_pretty(pg_relation_size(C.oid)) AS "size"
ptrdb04-> FROM pg_class C
ptrdb04-> LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
ptrdb04-> WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ptrdb04-> ORDER BY pg_relation_size(C.oid) DESC
ptrdb04-> LIMIT 2;
relação | tamanho
------------------------- + ---------
pg_toast . pg_toast_17269 | 18 GB
somes00 . warmstates | 1224 MB
( 2 linhas )
VACUUM VERBOSE ANALYZE timeseries;
INFO: "timeseries": encontrado 12699 removíveis, 681961 versões de linhas não removíveis em 58130 das 68382 páginas DETALHE: 0 versões de linhas mortas ainda não podem ser removidas. Havia 105847 ponteiros de itens não utilizados. 0 páginas estão completamente vazias. CPU 0,83s / 2,08u s decorridos 33,36 s. INFO: limpando "pg_toast.pg_toast_17269" INFO: índice verificado "pg_toast_17269_index" para remover as versões de linha 2055849 DETALHE: CPU 0.37s / 2.92u seg decorridos 13.29 seg. INFO: "pg_toast_17269": removidas 2055849 versões de linha em 518543 páginas DETALHE: CPU 8.60s / 3.21u seg decorridos 358.42 seg. INFO: o índice "pg_toast_17269_index" agora contém 7346902 versões de linha em 36786 páginas DETALHE: as versões de linha de índice 2055849 foram removidas. 10410 páginas de índice foram excluídas, 5124 são atualmente reutilizáveis. CPU 0.00s / 0.00u seg. Decorrido 0.01 seg. INFO: "pg_toast_17269": encontrada 1286128 removível, 2993389 versões de linha não removíveis em 1257871 de 2328079 páginas DETALHE: 0 versões de linhas mortas ainda não podem ser removidas. Havia 18847 ponteiros de itens não utilizados. 0 páginas estão completamente vazias. CPU 26.56s / 13.04u seg decorrido 714.97 seg. INFO: analisando "poucas séries00.tempos" INFO: "timeseries": digitalizadas 30000 de 68382 páginas, contendo 360192 linhas ativas e 0 linhas mortas; 30000 linhas na amostra, 821022 total de linhas estimadas
A única diferença perceptível após a reconstrução (além do uso do disco) é
INFO: "pg_toast_17269": encontrado 1286128 removível, 2993389 versões de linha não removíveiscomo @CraigRinger mencionado em um comentário. A contagem de linhas não removíveis é muito menor do que antes.
Nova pergunta: outras tabelas podem afetar o tamanho de outra tabela? (por meio de chaves estrangeiras e coisas do tipo) A reconstrução da tabela não fez nada, mas a reconstrução de todo o banco de dados provou corrigir o problema.