2012-10-17 14 views
8

Ich habe einen großen Tisch mit 10m Reihen. Und ich muss für jede Zeile einen statistischen Wert erhalten. Ich habe eine Funktion, die diesen Wert erzeugt, zum Beispiel GetStatistic(uuid). Diese Funktion arbeitet sehr langsam und Ergebniswert ändert sich nicht oft, also habe ich Spalte Statistic in meiner Tabelle erstellt, und einmal pro Tag ausführen Abfrage wie folgt:PostgreSQL. Kann Update-Abfrage parallel ausgeführt werden?

UPDATE MyTable SET Statistic = GetStatistic(ID); 

Und in SELECT-Abfragen verwenden i Spalte Statistic ohne GetStatistic Aufruf Funktionen.

Problem ist, dass mein Produktionsserver 64 CPUs und viel Speicher hat, so dass fast alle DB im RAM zwischengespeichert werden können, aber diese Abfrage verwendet nur eine CPU und benötigt 2 oder 3 Stunden zur Ausführung.

GetStatistic-Funktion Verwendungstabelle, die während der Ausführung der UPDATE-Abfrage konstant ist. Kann ich die Abfrage ändern, um Postgre zu erhalten, um GetStatistic parallel für verschiedene Zeilen gleichzeitig zu berechnen, wobei alle verfügbaren CPUs verwendet werden?

+0

Warum eine Funktion verwenden, gibt es etwas, das nicht durch einfaches SQL erreicht werden kann? Benötigt die Funktion nur Werte aus der aktuellen Zeile oder bezieht sie sich auch auf andere Datenquellen (: = Tabellen)? BTW: zeigen Sie uns die Funktion. – wildplasser

+0

Überprüfen Sie den Plan dieser Abfrage, Sie werden sehen, dass diese Funktion 10M mal aufgerufen wird. Vielleicht wäre es besser, es in reinem SQL zu schreiben und es könnte viel schneller sein. –

Antwort

9

PostgreSQL führt jede Abfrage in einem einzigen Backend aus, was ein Prozess mit einem einzelnen Thread ist. Es kann nicht mehr als eine CPU für eine Abfrage verwenden. Es ist auch etwas eingeschränkt, was E/A-Parallelität innerhalb einer einzelnen Abfrage erreichen kann, wobei es nur gleichzeitige I/O für Bitmap-Index-Scans durchführt und sich ansonsten auf das Betriebssystem und das Plattensystem für gleichzeitige I/O verlässt.

Pg ist gut bei gleichzeitigen Abfragen vieler kleinerer Abfragen und es ist einfach, Ihr System auf diese Weise zu sättigen, es ist einfach nicht so gut, das Beste aus Systemressourcen für eine oder zwei wirklich große Abfragen zu machen.

Was Sie tun können, ist, den Job in Stücke aufzuteilen und sie an Arbeiter zu verteilen. Sie haben dazu anspielte mit:

Kann ich Abfrage ändern, um postgre zu erhalten GetStatistic in paralel für verschiedene Zeilen gleichzeitig zu berechnen, alle verfügbaren CPUs?

Es gibt eine Vielzahl von Werkzeugen, wie DBlink, PL/Proxy, pgbouncer und PgPool-II die entworfen sind, mit dieser Art von Arbeit zu helfen. Alternativ können Sie es auch selbst tun, indem Sie (zum Beispiel) 8 Worker starten, die sich jeweils mit der Datenbank verbinden und UPDATE ... WHERE id BETWEEN ? AND ? Anweisungen mit nicht überlappenden ID-Bereichen ausführen. Eine ausgeklügeltere Option besteht darin, dass ein Warteschlangen-Controller Bereiche von ungefähr 1000 IDs an Arbeiter verteilt, die dann diesen Bereich anfordern und dann nach einem neuen fragen.

Beachten Sie, dass 64 CPUs nicht bedeutet, dass 64 gleichzeitige Arbeiter ideal ist. Ihre Festplatten-E/A ist auch ein Faktor, wenn es um Schreibvorgänge geht. Sie können Ihren E/A-Kosten ein wenig helfen, wenn Sie Ihre UPDATE Transaktionen verwenden, um eine commit_delay zu verwenden, und (wenn für Ihre Geschäftsanforderungen für diese Daten sicher) synchronous_commit = 'off' dann die Last von Syncs sollte erheblich reduziert werden. Nichtsdestoweniger ist es wahrscheinlich, dass der beste Durchsatz deutlich unter 64 gleichzeitigen Arbeitern erreicht wird.

Es ist sehr wahrscheinlich, dass Ihre GetStatistic-Funktion viel schneller gemacht werden kann, indem Sie sie in eine inlineable SQL-Funktion oder View konvertieren, anstatt eine Schleife-schwere prozedurale PL/pgSQL-Funktion ist es im Moment. Es könnte hilfreich sein, wenn Sie diese Funktion angezeigt haben.

Verwandte Themen