Quelqu'un pourrait-il m'expliquer ce comportement? J'ai exécuté la requête suivante sur Postgres 9.3 fonctionnant en mode natif sur OS X. J'essayais de simuler un comportement où la taille de l'index pouvait augmenter beaucoup plus que la taille de la table, et j'ai trouvé quelque chose de plus bizarre.
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);
J'ai laissé cela s'exécuter pendant environ une heure sur ma machine locale, avant de commencer à recevoir des avertissements de problème de disque d'OS X. J'ai remarqué que Postgres aspirait environ 10 Mo / s de mon disque local et que la base de données Postgres consommait un grand total de 30 Go de ma machine. J'ai fini par annuler la requête. Quoi qu'il en soit, Postgres ne m'a pas renvoyé l'espace disque et j'ai interrogé la base de données pour obtenir des statistiques d'utilisation avec le résultat suivant:
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
Cependant, la sélection dans le tableau n'a donné aucun résultat.
test=# select * from test limit 1;
id
----
(0 rows)
L'exécution de 10 000 lots de 500 correspond à 5 000 000 de lignes, ce qui devrait donner une taille de table / d'index assez petite (sur l'échelle de Mo). Je soupçonne que Postgres crée une nouvelle version de la table / index pour chaque INSERT / UPDATE qui se passe avec la fonction, mais cela semble étrange. La fonction entière est exécutée de manière transactionnelle et la table était vide pour démarrer.
Avez-vous des raisons de penser à ce comportement?
Plus précisément, les deux questions que je me pose sont les suivantes: pourquoi cet espace n'a-t-il pas encore été récupéré par la base de données et la seconde est pourquoi la base de données a-t-elle exigé autant d'espace en premier lieu? 30 Go semble beaucoup même en tenant compte de MVCC