Sie können das ausführen, kein Problem:
VACUUM FULL ANALYZE pg_largeobject;
Könnte sogar einige tote Reihen entfernen. Einzelheiten:
Aber es wird wahrscheinlich Ihr eigentliches Problem nicht lösen .
Bei Verwendung des großen Objekts Anlage von Postgres , große Objekte ( "blob": binary large object) selbst sind in chuncks von binären Daten in der Systemtabelle gespeichert aufgebrochen pg_largeobject
. Die PK besteht aus zwei Spalten (loid, pageno)
und loid
wird oid
verwendet, um auf den Blob in Benutzertabellen zu verweisen. Auf denselben Blob kann von OID viele Male verwiesen werden.
Durch das Löschen von Zeilen in Benutzertabellen wird der Blob nicht entfernt. Zum einen kann derselbe Blob mehr als einmal referenziert werden. Es liegt in Ihrer Verantwortung, den Überblick zu behalten und "nicht verknüpfte" Blobs selbst zu löschen. Ein Weg wäre zu verwenden lo_unlink()
:
SELECT lo_unlink(173454); -- deletes large object with OID 173454
Da Sie bereits Zeilen mit der oid
Referenz gelöscht haben , müssen Sie etwas kreativer sein, um nicht verknüpfte Blobs zu identifizieren. Angenommen, Sie verweisen nicht auf Blobs von anderen Stellen, können Sie diese Abfrage verwenden, um Folgendes zu beheben :
SELECT lo_unlink(l.loid)
FROM pg_largeobject l
GROUP BY loid
HAVING (NOT EXISTS (SELECT 1 FROM table1 t WHERE t.oid = l.loid))
AND (NOT EXISTS (SELECT 1 FROM table2 t WHERE t.oid = l.loid));
Sie müssen Superuser sein , um pg_largeobject
direkt darauf zugreifen zu können. Angenommen, der Spaltenname in table1
und table2
ist oid
. Einfachere Abfrage basierend auf pg_largeobject_metadata
Postgres 9.3 oder höher (wie @Daniel kommentiert ):
SELECT lo_unlink(l.oid)
FROM pg_largeobject_metadata l
WHERE (NOT EXISTS (SELECT 1 FROM table1 WHERE t.oid = l.oid))
AND (NOT EXISTS (SELECT 1 FROM table2 WHERE t.oid = l.oid));
pg_largeobject_metadata
ist öffentlich lesbar. Aber ich sehe die OID des Blobs in der Systemtabelle in Versionen vor S. 9.3 (inkl. S. 9.1) nicht - zumindest nicht im Handbuch, ich habe momentan keine alte Version zum Testen. Sie müssen also wahrscheinlich meine erste Abfrage verwenden.
Vergleichen Sie vorher und nachher:
SELECT count(*) FROM pg_largeobject;
SELECT pg_size_pretty(pg_table_size('pg_largeobject'));
Sie können VACUUM FULL
jetzt ausführen und erneut testen:
VACUUM FULL ANALYZE pg_largeobject;
Sie werden an dem zusätzlichen Modullo
interessiert sein , das für Postgres 9.1 verfügbar ist. Das Handbuch enthält eine genaue Beschreibung Ihres Problems:
... ein Tabelleneintrag kann ein großes Objekt anhand der OID referenzieren, es können jedoch mehrere Tabelleneinträge vorhanden sein, die auf dieselbe OID für große Objekte verweisen, sodass das System das große Objekt nicht löscht, nur weil Sie einen solchen Eintrag ändern oder entfernen.
Meine kühne Betonung. Das Modul bietet auch eine Lösung:
Das lo
Modul ermöglicht das Beheben dieses Problems, indem Tabellen, die LO-Referenzspalten enthalten, ein Trigger hinzugefügt wird. Der Trigger führt im Wesentlichen nur dann eine
lo_unlink
Aktion aus, wenn Sie einen Wert löschen oder ändern, der auf ein großes Objekt verweist.
Für Anwendungsfälle, in denen jeder Blob in Ihrer gesamten Datenbank genau einmal referenziert wird .
Und natürlich auch (wie @Daniel erwähnt ) vacuumlo
:
Vakuumlo ist ein einfaches Hilfsprogramm, das alle "verwaisten" großen Objekte aus einer PostgreSQL-Datenbank entfernt.
pg_largeobject_metadata
anstelle von verwendenpg_largeobject
. Das macht Vakuumlo . Es ist viel leichter und öffentlich lesbar.pg_largeobject_metadata
für Versionen vor S. 9.3 - was (seltsamerweise!) Den Anweisungen auf der Seite für widersprichtpg_largeobject
. Ich habe der Antwort Details hinzugefügt. Haben Sie mit Seite 9.1 getestet?oid
nicht dokumentiert werden. Ich stelle fest, dass es dasselbe ist,pg_class
also denke ich, dass es eine allgemeine Sache ist; ab 9.3 wurde anscheinend entschieden, dass wenn diesoid
in einer systemtabelle relevant ist, diese explizit aufgelistet werden sollte. Macht Sinn.