Qualcuno potrebbe spiegarmi questo comportamento? Ho eseguito la seguente query su Postgres 9.3 in modo nativo su OS X. Stavo cercando di simulare un comportamento in cui la dimensione dell'indice poteva aumentare molto più della dimensione della tabella, e invece ho trovato qualcosa di ancora più bizzarro.
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);
L'ho lasciato funzionare per circa un'ora sul mio computer locale, prima di iniziare a ricevere avvisi sul problema del disco da OS X. Ho notato che Postgres stava succhiando circa 10 MB / s dal mio disco locale e che il database Postgres stava consumando un totale di 30 GB dalla mia macchina. Ho finito per annullare la query. Indipendentemente da ciò, Postgres non mi ha restituito lo spazio su disco e ho richiesto al database le statistiche sull'utilizzo con il seguente risultato:
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
Tuttavia, la selezione dalla tabella non ha prodotto risultati.
test=# select * from test limit 1;
id
----
(0 rows)
L'esecuzione di 10000 batch di 500 è di 5.000.000 di righe, il che dovrebbe produrre una tabella / dimensione dell'indice piuttosto piccola (sulla scala di MB). Sospetto che Postgres stia creando una nuova versione della tabella / indice per ogni INSERT / UPDATE che sta accadendo con la funzione, ma questo sembra strano. L'intera funzione viene eseguita in modo transazionale e la tabella era vuota per l'avvio.
Qualche idea sul perché sto vedendo questo comportamento?
In particolare, le due domande che ho sono: perché questo spazio non è stato ancora recuperato dal database e il secondo è perché il database ha richiesto così tanto spazio in primo luogo? 30 GB sembra molto anche quando si contabilizza MVCC