PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Der beste Weg, um Millionen von Zeilen nach ID zu löschen

Es hängt alles davon ab ...

  • Vorausgesetzt kein gleichzeitiger Schreibzugriff zu beteiligten Tabellen oder Sie müssen Tabellen exklusiv sperren oder diese Route ist überhaupt nicht für Sie geeignet.

  • Löschen Sie alle Indizes (evtl. außer denen, die zum Löschen selbst benötigt werden).
    Erstellen Sie diese anschließend neu. Das ist in der Regel viel schneller als inkrementelle Aktualisierungen von Indizes.

  • Prüfen Sie, ob Sie Auslöser haben, die sicher gelöscht/vorübergehend deaktiviert werden können.

  • Verweisen Fremdschlüssel auf Ihre Tabelle? Können sie gelöscht werden? Vorübergehend gelöscht?

  • Abhängig von Ihren Autovacuum-Einstellungen kann dies der Fall sein helfen, VACUUM ANALYZE auszuführen vor der Operation.

  • Einige der Punkte, die im entsprechenden Kapitel des Handbuchs Befüllen einer Datenbank aufgeführt sind kann auch von Nutzen sein, abhängig von Ihrem Setup.

  • Wenn Sie große Teile der Tabelle löschen und der Rest in den Arbeitsspeicher passt, ist der schnellste und einfachste Weg möglicherweise dieser:

BEGIN; -- typically faster and safer wrapped in a single transaction

SET LOCAL temp_buffers = '1000MB'; -- enough to hold the temp table

CREATE TEMP TABLE tmp AS
SELECT t.*
FROM   tbl t
LEFT   JOIN del_list d USING (id)
WHERE  d.id IS NULL;      -- copy surviving rows into temporary table

TRUNCATE tbl;             -- empty table - truncate is very fast for big tables

INSERT INTO tbl
SELECT * FROM tmp;        -- insert back surviving rows.
-- ORDER BY ?             -- optionally order favorably while being at it

COMMIT;

Auf diese Weise müssen Sie Ansichten, Fremdschlüssel oder andere abhängige Objekte nicht neu erstellen. Und Sie erhalten eine makellose (sortierte) Tabelle ohne Aufblasen.

Lesen Sie mehr über die temp_buffers Einstellung im Handbuch. Diese Methode ist schnell, solange die Tabelle in den Speicher passt, oder zumindest den größten Teil davon. Der Transaktionswrapper schützt vor Datenverlust, wenn Ihr Server mitten in diesem Vorgang abstürzt.

Führen Sie VACUUM ANALYZE aus nachher. Oder VACUUM FULL ANALYZE wenn Sie es auf die minimale Größe bringen möchten (nimmt exklusive Sperre). Betrachten Sie für große Tabellen die Alternativen CLUSTER / pg_repack oder ähnlich:

  • Optimieren Sie den Abfragebereich für Postgres-Zeitstempel

Für kleine Tabellen ein einfaches DELETE statt TRUNCATE ist oft schneller:

DELETE FROM tbl t
USING  del_list d
WHERE  t.id = d.id;

Lesen die Notizen Abschnitt für TRUNCATE im Handbuch. Insbesondere (wie Pedro auch in seinem Kommentar betonte):

TRUNCATE kann nicht für eine Tabelle verwendet werden, die Fremdschlüsselreferenzen aus anderen Tabellen enthält, es sei denn, alle diese Tabellen werden im selben Befehl ebenfalls abgeschnitten. [...]

Und:

TRUNCATE wird kein ON DELETE auslösen Trigger, die möglicherweise für die Tabellen vorhanden sind.