¿Podría alguien explicarme este comportamiento? Ejecuté la siguiente consulta en Postgres 9.3 ejecutándose de forma nativa en OS X. Intenté simular algún comportamiento en el que el tamaño del índice podría crecer mucho más que el tamaño de la tabla, y en su lugar encontré algo aún más extraño.
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);
Dejé que esto se ejecute durante aproximadamente una hora en mi máquina local, antes de comenzar a recibir advertencias de problemas de disco de OS X. Noté que Postgres estaba absorbiendo aproximadamente 10 MB / s de mi disco local, y que la base de datos de Postgres estaba consumiendo un gran total de 30GB desde mi máquina. Terminé cancelando la consulta. De todos modos, Postgres no me devolvió el espacio en disco y pregunté a la base de datos las estadísticas de uso con el siguiente 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
Sin embargo, la selección de la tabla no arrojó resultados.
test=# select * from test limit 1;
id
----
(0 rows)
Ejecutar 10000 lotes de 500 es 5,000,000 filas, lo que debería producir un tamaño de tabla / índice bastante pequeño (en la escala de MB). Sospecho que Postgres está creando una nueva versión de la tabla / índice para cada INSERTAR / ACTUALIZAR que sucede con la función, pero esto parece extraño. Toda la función se ejecuta transaccionalmente y la tabla estaba vacía para comenzar.
¿Alguna idea de por qué estoy viendo este comportamiento?
Específicamente, las dos preguntas que tengo son: ¿por qué este espacio aún no ha sido reclamado por la base de datos y el segundo es por qué la base de datos requirió tanto espacio en primer lugar? 30 GB parece mucho, incluso cuando se cuenta con MVCC