Könnte mir jemand dieses Verhalten erklären? Ich habe die folgende Abfrage unter Postgres 9.3 ausgeführt, das nativ unter OS X ausgeführt wird. Ich habe versucht, ein Verhalten zu simulieren, bei dem die Indexgröße viel größer als die Tabellengröße werden kann, und stattdessen etwas noch Seltsameres gefunden.
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);
Ich ließ dies ungefähr eine Stunde lang auf meinem lokalen Computer laufen, bevor ich von OS X Warnungen zu Festplattenproblemen erhielt. Ich bemerkte, dass Postgres ungefähr 10 MB / s von meiner lokalen Festplatte aufsaugte und dass die Postgres-Datenbank eine Gesamtsumme verbrauchte von 30 GB von meinem Computer. Am Ende habe ich die Abfrage abgebrochen. Unabhängig davon hat Postgres den Speicherplatz nicht an mich zurückgegeben, und ich habe die Datenbank nach Nutzungsstatistiken mit dem folgenden Ergebnis abgefragt:
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
Die Auswahl aus der Tabelle ergab jedoch keine Ergebnisse.
test=# select * from test limit 1;
id
----
(0 rows)
Das Ausführen von 10000 500er-Batches umfasst 5.000.000 Zeilen, was eine ziemlich kleine Tabellen- / Indexgröße (auf der MB-Skala) ergeben sollte. Ich vermute, dass Postgres für jedes INSERT / UPDATE, das mit der Funktion geschieht, eine neue Version der Tabelle / des Index erstellt, aber das scheint seltsam. Die gesamte Funktion wird transaktional ausgeführt, und die Tabelle war zum Starten leer.
Irgendwelche Gedanken darüber, warum ich dieses Verhalten sehe?
Die beiden Fragen, die ich habe, lauten insbesondere: Warum wurde dieser Speicherplatz noch nicht von der Datenbank zurückgefordert, und die zweite Frage ist, warum die Datenbank überhaupt so viel Speicherplatz benötigt hat. 30 GB scheinen viel zu sein, selbst wenn MVCC berücksichtigt wird