it-swarm.com.de

Wie kann man in Postgresql Millionen von Zeilen effizient von einer Tabelle in eine andere kopieren?

Ich habe zwei Datenbanktabellen. Eine enthält Hunderte Millionen Datensätze. Nennen wir das history. Der andere wird täglich berechnet und ich möchte alle seine Datensätze in den history kopieren.

Was ich getan habe war zu rennen:

INSERT INTO history SELECT * FROM daily

Und es hat den Trick für eine Weile gemacht, aber es wurde immer langsamer, als die Anzahl der Datensätze weiter zunahm. Jetzt habe ich ungefähr 2 Millionen Datensätze, die in einem einzigen Vorgang von daily nach history kopiert werden müssen, und die Fertigstellung dauert zu lange.

Gibt es eine andere, effizientere Möglichkeit, Daten von einer Tabelle in eine andere zu kopieren?

38
Milovan Zogovic

Wenn Sie den Verlauf über einen längeren Zeitraum (viele Monate) aufbewahren möchten, sollten Sie sich die Partitionierungsoptionen ansehen - möglicherweise eine Partition für jeden Tag oder jede Woche usw. Dies hängt auch von den Zugriffsmustern Ihrer Verlaufstabelle ab (führen Sie Abfragen aus, die datumsübergreifend auf Daten zugreifen? Führen Sie viele Aggregationen usw. durch). Schauen Sie sich materialisierte Ansichten zum Speichern von Aggregaten/Zusammenfassungen an. http://www.postgresql.org/docs/9.3/static/ddl-partitioning.htmlhttp://www.postgresql.org/docs/9.3/static/sql- creatematerializedview.html

10
Jayadevan

Speichern Sie die Tabelle im CSV-Format

COPY table TO '/tmp/table.csv' DELIMITER ',';

verwenden Sie den Befehl COPY, der für große Datenmengen weitaus effizienter ist.

COPY table FROM '/tmp/table.csv' DELIMITER ',';

Weitere Informationen finden Sie in den Postgres-Dokumenten unter http://www.postgresql.org/docs/current/static/sql-copy.html

16

Das Problem war mit Indizes. Die Tabelle history hatte 160 Millionen indizierte Zeilen. Durch Ausführen von COPY FROM oder INSERT INTO .. SELECT Es hat viel Zeit gekostet, keine Zeilen einzufügen, sondern Indizes zu aktualisieren. Wenn ich Indizes deaktiviert habe, wurden 3 Millionen Zeilen in 10 Sekunden importiert. Jetzt muss ich einen schnelleren Weg finden, um den großen Tisch neu zu indizieren.

14
Milovan Zogovic

Sie können das Tool psql verwenden, ich könnte wie folgt effizient sein:

psql -h ${DAILY_Host_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME} -c "copy daily to stdout " | psql -h ${HISTORY_Host_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME}  -c "copy history from stdin"

Sie können auch ein Shell-Skript schreiben.

11
francs

Dies ist natürlich keine genaue Antwort auf Ihre Frage, aber wenn Sie nicht auf die Tabelle history zugreifen müssen, können Sie auch einen SQL-Dump generieren:

pg_dump -h Host -p port -w -U user db > dump.sql

Dann könnte man ein Werkzeug wie git verwenden, um die Differenz zu berechnen und diese effizient zu speichern.

git add dump.sql
git commit -m "temp dump"
git gc --aggressive

Dies ist nützlich, da sich die meisten Teile in einer Datenbank nicht jeden Tag ändern. Anstatt für jeden Tag eine ganze Kopie zu speichern, kann man die Differenz zwischen zwei Tagen speichern.

Sie können einen crontab -Job verwenden, sodass der Speicherauszug jeden Tag verarbeitet wird.

3