Kann ich VACUUM FULL für die Tabelle pg_largeobject ausführen?

7

Ich habe zwei Tabellen ( table1, table2) in einer Postgres 9.1-Datenbank. Beide haben einen Oid-Typ. Jede Tabelle 1 Million Datensätze. Die pg_largeobjectTischgröße beträgt ca. 40 GB. Ich habe 0,9 Millionen Datensätze aus jeder Tabelle entfernt und den folgenden Befehl ausgeführt.

vacuum full analyze table1;
vacuum full analyze table2;

Immer noch keine Änderung der pg_largeobjectTischgröße (automatisches Vakuum ist aktiviert)

Muss ich den obigen Befehl auch für die pg_largeobjectTabelle ausführen ? Wird es irgendetwas beeinflussen?

Spitze
quelle

Antworten:

10

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 loidwird oidverwendet, 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 oidReferenz 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_largeobjectdirekt darauf zugreifen zu können. Angenommen, der Spaltenname in table1und table2ist oid. Einfachere Abfrage basierend auf pg_largeobject_metadataPostgres 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_metadataist ö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 FULLjetzt 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 loModul 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_unlinkAktion 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.

Erwin Brandstetter
quelle
1
Um die bloße Existenz eines großen Objekts abzufragen, sollten wir in PG 9.0+ pg_largeobject_metadataanstelle von verwenden pg_largeobject. Das macht Vakuumlo . Es ist viel leichter und öffentlich lesbar.
Daniel Vérité
@ DanielVérité: Guter Punkt. Das Handbuch zeigt jedoch nicht das Blob-Oid in pg_largeobject_metadatafür Versionen vor S. 9.3 - was (seltsamerweise!) Den Anweisungen auf der Seite für widerspricht pg_largeobject. Ich habe der Antwort Details hinzugefügt. Haben Sie mit Seite 9.1 getestet?
Erwin Brandstetter
1
Die Änderung erfolgte bereits am 14. Dezember 2009 in Commit 84f910a707: Verwenden Sie pg_largeobject_metadata.oid anstelle von pg_largeobject.loid, um vorhandene große Objekte in pg_dump usw. aufzulisten.
Daniel Vérité
1
Über oidnicht dokumentiert werden. Ich stelle fest, dass es dasselbe ist, pg_classalso denke ich, dass es eine allgemeine Sache ist; ab 9.3 wurde anscheinend entschieden, dass wenn dies oidin einer systemtabelle relevant ist, diese explizit aufgelistet werden sollte. Macht Sinn.
Daniel Vérité
Das würde es erklären.
Erwin Brandstetter