Alguém poderia me explicar esse comportamento? Eu executei a seguinte consulta no Postgres 9.3 executando nativamente no OS X. Eu estava tentando simular algum comportamento em que o tamanho do índice pudesse crescer muito maior que o tamanho da tabela e, em vez disso, achei algo ainda mais bizarro.
CREATE TABLE test(id int);
CREATE INDEX test_idx ON test(id);
CREATE FUNCTION test_index(batch_size integer, total_batches integer) RETURNS void AS $$
DECLARE
current_id integer := 1;
BEGIN
FOR i IN 1..total_batches LOOP
INSERT INTO test VALUES (current_id);
FOR j IN 1..batch_size LOOP
UPDATE test SET id = current_id + 1 WHERE id = current_id;
current_id := current_id + 1;
END LOOP;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT test_index(500, 10000);
Eu deixei isso funcionar por cerca de uma hora na minha máquina local, antes de começar a receber avisos de problemas de disco do OS X. Notei que o Postgres estava sugando cerca de 10 MB / s do meu disco local e que o banco de dados do Postgres estava consumindo um total geral. de 30 GB da minha máquina. Acabei cancelando a consulta. Independentemente disso, o Postgres não retornou o espaço em disco para mim e consultei o banco de dados para obter estatísticas de uso com o seguinte resultado:
test=# 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;
relation | size
-------------------------------+------------
public.test | 17 GB
public.test_idx | 14 GB
No entanto, a seleção na tabela não produziu resultados.
test=# select * from test limit 1;
id
----
(0 rows)
A execução de 10000 lotes de 500 é de 5.000.000 de linhas, o que deve gerar um tamanho muito pequeno de tabela / índice (na escala de MB). Eu suspeito que o Postgres esteja criando uma nova versão da tabela / índice para cada INSERT / UPDATE que está acontecendo com a função, mas isso parece estranho. Toda a função é executada transacionalmente e a tabela estava vazia para iniciar.
Alguma idéia de por que estou vendo esse comportamento?
Especificamente, as duas perguntas que tenho são: por que esse espaço ainda não foi recuperado pelo banco de dados e a segunda é por que o banco de dados exigiu tanto espaço em primeiro lugar? 30 GB parece muito, mesmo quando se considera o MVCC