Die effizienteste Möglichkeit, einer großen Tabelle eine serielle Spalte hinzuzufügen

10

Was ist der schnellste Weg, um einer großen Tabelle eine BIGSERIAL-Spalte hinzuzufügen (~ 3 Bil. Zeilen, ~ 174 GB)?

BEARBEITEN:

  • Ich möchte, dass die Spalte inkrementierte Werte für vorhandene Zeilen ( NOT NULL) enthält.
  • Ich habe keinen Füllfaktor eingestellt (was im Nachhinein nach einer schlechten Entscheidung aussieht).
  • Ich habe kein Problem mit dem Speicherplatz, möchte nur, dass er so schnell wie möglich ist.
Thi Duong Nguyen
quelle

Antworten:

12

Was ist falsch mit:

ALTER TABLE foo ADD column bar bigserial;

Wird automatisch mit eindeutigen Werten gefüllt (beginnend mit 1).

Wenn Sie für jede vorhandene Zeile eine Nummer wünschen, muss jede Zeile in der Tabelle aktualisiert werden . Oder nicht?

Die Tabelle wird auf die doppelte Größe aufgebläht, wenn tote Tupel oder freier Speicherplatz auf den Datenseiten nicht wiederverwendet werden können. Die Leistung der Operation kann stark von FILLFACTORweniger als 100 oder nur zufälligen toten Tupeln profitieren , die über den Tisch verteilt sind. Andernfalls möchten Sie möglicherweise VACUUM FULL ANALYZEspäter ausführen , um Speicherplatz wiederherzustellen. Dies wird jedoch nicht schnell gehen.

pgstattuple
Diese Erweiterung könnte Sie interessieren. Es hilft Ihnen, Statistiken über Ihre Tabellen zu sammeln. Um mehr über tote Tupel und freien Speicherplatz zu erfahren:

Installieren Sie die Erweiterung einmal pro Datenbank:

CREATE EXTENSION pgstattuple;

Anruf:

SELECT * FROM pgstattuple('tbl');

Alternative

Wenn Sie es sich leisten können, eine neue Tabelle zu erstellen, die je nach Ansicht, Fremdschlüssel, ...

Erstellen Sie eine leere Kopie der alten Tabelle:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

Fügen Sie die Bigserial-Spalte hinzu:

ALTER new_tbl ADD column bar bigserial;

INSERT-Daten aus alter Tabelle, die das Bigserial automatisch ausfüllen:

INSERT INTO new_tbl
SELECT *    --  new column will be filled with default
FROM   old_tbl
ORDER  BY something; -- or don't order if you don't care: faster

Die neue Bigserial-Spalte fehlt in SELECT des INSERT und wird automatisch mit ihrem Standardwert gefüllt . Sie können alle Spalten buchstabieren und mit demselben Effekt nextval()zur SELECTListe hinzufügen .

Stellen Sie sicher, dass Sie alle Ihre Daten in der neuen Tabelle haben.
Fügen Sie Indizes, Einschränkungen und Trigger hinzu, die Sie jetzt in der alten Tabelle hatten .

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

Könnte insgesamt etwas schneller sein. So haben Sie eine Vanille-Tabelle (und Indizes) ohne Aufblähen.

Sie benötigen freien Speicherplatz - ungefähr so ​​groß wie die alte Tabelle, abhängig vom Status der Tabelle - als Spielraum. Bei der ersten einfachen Methode benötigen Sie möglicherweise genau so viel, weil der Tisch aufgebläht ist. Auch hier hängen die Details vom Status Ihrer Tabelle ab.

Erwin Brandstetter
quelle
3
Wickeln Sie die Alternative in eine einzige Transaktion ein, die viel schneller sein wird. Es wird zusätzliche fsyncs vermeiden
Frank Heikens