Verwendung von PG 9.1 unter Ubuntu 12.04.
Derzeit dauert es bis zu 24 Stunden, bis wir eine große Anzahl von UPDATE-Anweisungen in einer Datenbank ausgeführt haben, die folgende Form haben:
UPDATE table
SET field1 = constant1, field2 = constant2, ...
WHERE id = constid
(Wir überschreiben nur Felder von Objekten, die durch ID gekennzeichnet sind.) Die Werte stammen aus einer externen Datenquelle (nicht bereits in der Datenbank in einer Tabelle).
Die Tabellen haben jeweils eine Handvoll Indizes und keine Fremdschlüsseleinschränkungen. Bis zum Ende wird kein COMMIT durchgeführt.
Es dauert 2 Stunden, um eine pg_dump
der gesamten DB zu importieren . Dies scheint eine Grundlinie zu sein, auf die wir angemessen zielen sollten.
Abgesehen von der Erstellung eines benutzerdefinierten Programms, das einen Datensatz für den erneuten Import von PostgreSQL auf irgendeine Weise rekonstruiert, können wir noch etwas tun, um die UPDATE-Massenleistung näher an die des Imports heranzuführen? (Dies ist ein Bereich, der unserer Meinung nach mit logarithmisch strukturierten Zusammenführungsbäumen gut zurechtkommt, aber wir fragen uns, ob wir in PostgreSQL etwas tun können.)
Einige Ideen:
- Alle Nicht-ID-Indizes löschen und danach neu erstellen?
- Steigern Sie checkpoint_segments, aber hilft dies tatsächlich, den Durchsatz langfristig aufrechtzuerhalten?
- Verwenden Sie die hier genannten Techniken ? (Neue Daten als Tabelle laden, dann alte Daten "zusammenführen", wobei ID in neuen Daten nicht gefunden wird.)
Grundsätzlich gibt es eine Menge Dinge zu versuchen und wir sind uns nicht sicher, welche am effektivsten sind oder ob wir andere Dinge übersehen. Wir werden die nächsten Tage damit verbringen, zu experimentieren, aber wir dachten, wir würden auch hier nachfragen.
Die Tabelle ist zwar gleichzeitig geladen, aber schreibgeschützt.
explain analyze
ob ein Index für die Suche verwendet wird.Antworten:
Annahmen
Da Informationen im Q fehlen, gehe ich davon aus:
COPY
Ausgabe formatiert , und zwar mit einer eindeutigen Angabeid
pro Zeile, die mit der Zieltabelle übereinstimmt.Wenn nicht, formatieren Sie es zuerst richtig oder verwenden Sie die
COPY
Optionen, um das Format zu verarbeiten.Das bedeutet keinen gleichzeitigen Zugriff. Andernfalls betrachten Sie diese verwandte Antwort:
Lösung
Ich schlage vor, Sie gehen mit einem ähnlichen Ansatz vor, wie unter dem Link von Ihrem dritten Aufzählungszeichen beschrieben . Mit großen Optimierungen.
Es gibt einen einfacheren und schnelleren Weg, um die temporäre Tabelle zu erstellen:
Ein einzelner Big
UPDATE
aus einer temporären Tabelle in der Datenbank ist um mehrere Größenordnungen schneller als einzelne Aktualisierungen von außerhalb der Datenbank.In PostgreSQLs MVCC Modell , ein
UPDATE
Mittel , eine neue Zeile Version und markieren Sie die alten zu erstellen , wie gelöscht. Das ist ungefähr so teuer wie eineINSERT
und eineDELETE
Kombination. Außerdem bleiben viele tote Tupel übrig. Da Sie ohnehin die gesamte Tabelle aktualisieren, ist es insgesamt schneller, eine neue Tabelle zu erstellen und die alte zu löschen.Wenn Sie genug RAM zur Verfügung haben, stellen Sie
temp_buffers
(nur für diese Sitzung!) Hoch genug ein, um die temporäre Tabelle im RAM zu halten - bevor Sie etwas anderes tun.Führen Sie einen Test mit einer kleinen Stichprobe durch und verwenden Sie die db-Objektgrößenfunktionen, um eine Schätzung des RAM-Bedarfs zu erhalten :
Komplettes Drehbuch
Gleichzeitige Ladung
Gleichzeitige Operationen an der Tabelle (die ich in den Annahmen am Anfang ausgeschlossen habe) warten, sobald die Tabelle gegen Ende gesperrt ist, und schlagen fehl, sobald die Transaktion festgeschrieben ist, da der Tabellenname sofort in seine OID aufgelöst wird, aber Die neue Tabelle hat eine andere OID. Die Tabelle bleibt konsistent, aber gleichzeitige Vorgänge können eine Ausnahme erhalten und müssen wiederholt werden. Details in dieser verwandten Antwort:
UPDATE Route
Wenn Sie die
UPDATE
Route gehen (müssen) , löschen Sie einen Index, der während des Updates nicht benötigt wird, und erstellen Sie ihn anschließend neu. Es ist viel billiger, einen Index in einem Stück zu erstellen, als ihn für jede einzelne Zeile zu aktualisieren. Dies kann auch HOT-Updates ermöglichen .Ich habe
UPDATE
in dieser eng verwandten Antwort zu SO ein ähnliches Verfahren beschrieben .quelle
DROP TABLE
nimmt einAccess Exclusive Lock
. In beiden Fällen habe ich die Voraussetzung bereits oben in meiner Antwort aufgeführt:You can afford to drop and recreate the target table.
Es kann hilfreich sein, die Tabelle zu Beginn der Transaktion zu sperren. Ich schlage vor, Sie beginnen eine neue Frage mit allen relevanten Details Ihrer Situation, damit wir dem auf den Grund gehen können.CREATE TABLE tbl_new AS SELECT t.*, u.field1, u.field2 from tbl t NATURAL LEFT JOIN tmp_tbl u;
,LEFT JOIN
um Zeilen beizubehalten, für die es keine Aktualisierung gibt. NatürlichNATURAL
kann das zu jedem gültigenUSING()
oder geändert werdenON
.Wenn die Daten in einer strukturierten Datei verfügbar gemacht werden können, können Sie sie mit einem Wrapper für fremde Daten lesen und eine Zusammenführung für die Zieltabelle durchführen.
quelle
MERGE
ist es (noch) nicht in PostgreSQL implementiert . Die Implementierungen in anderen RDBMS variieren erheblich. Beachten Sie die Tag-Informationen fürMERGE
undUPSERT
.