Gibt es hier jemanden mit Erfahrung mit Postgres auf Azure?

Wir müssen für ein Kundenprojekt einen Postgres Server verwenden, der auf Azure läuft (“Azure Database for PostgreSQL flexible server”).

Wir haben eine recht komplexe Abfrage die massiv von einer Parallelisierung durch Postgres profitiert. In unseren Testsystemen (Postgres in einer Ubuntu VM) klappt das auch prima (z.B. mit max_parallel_workers_per_gather=4)

Auf dem Azure Server sehen wir aber im Execution Plan immer nur ein “Workers Planned: 1” und “Workers Launched: 1”. Die Instanz selber hat 8 vCPUs.

Weiß jemand, ob Microsoft da ein eigenes Süppchen kocht und man irgendwas zusätzlich konfigurieren muss? max_parallel_workers und max_worker_processes stehen auf 8.

Ich habe versucht parallel_tuple_cost und parallel_setup_cost auf sehr kleine Werte zu setzen, aber das ändert auch nichts. min_parallel_table_scan_size und min_parallel_index_scan_size stehen auf dem Default und die beteiligten Tabellen und Indizes sind deutlich größer als diese Werte (ich habe aber auch versucht, die mal auf lächerlich niedrige Werte zu setzen)

Wie gesagt: mit einer “Standardinstallation” unter Ubuntu kann man die Performance schön über max_parallel_workers_per_gather kontrollieren.

Mein Verdacht ist, dass Microsoft da irgendetwas anders macht. Ich finde aber in deren Doku nichts dazu.

Vielleicht musste ja schon jemand hier mit dem Azure System arbeiten und kennt das?

Könnte ich den Output von EXPLAIN (ANALYZE, BUFFERS, SETTINGS) SELECT ... sehen?

Ich darf ihn nur “obfuscated” zeigen: Gcyh | explain.depesz.com

Depesz scheint den Teil mit “Settings” im Plan zu entferne:

Settings: effective_cache_size = '24GB', jit = 'off', random_page_cost = '2', work_mem = '64MB', max_parallel_workers_per_gather = '4'

Laufzeit 46 Sekunden, komplett ohne I/O Overhead.

Wenn ich die Daten in unsere Entwicklungsdatenbank (Ubuntu VM) kopiere und die exakt gleiche Abfrage dort laufen lassen, dann sind es nur 17 Sekunden (incl. 2,5 Sekunden I/O): GoGa | explain.depesz.com

Settings dazu:

Settings: temp_buffers = '256MB', work_mem = '64MB', jit = 'off', max_parallel_workers_per_gather = '4', random_page_cost = '2', effective_cache_size = '10GB'

Die temp_buffers habe ich auch mal angepasst (sowohl bei uns als auch in der Azure Umgebung, die machen keinen Unterschied)

Also ich sehe da einmal

Workers Planned: 1
Workers Launched: 1

und einmal

Workers Planned: 4
Workers Launched: 0

Ich sehe also kein Problem, was das planen der Abfrage betrifft. Bei der Ausführung sind offenbar zu wenige parallele Hilfsprozesse im Pool, weil sie von anderen Statements verwendet werden.

Wenn man ein User mit den entsprechenden Berechtigungen ist, zeigt diese Abfrage alle jetzt laufenden parallelen Hilfsprozesse:

SELECT pid, datname, usename, query
FROM pg_stat_activity
WHERE backend_type = 'parallel worker';

Also ist Resource Contention das Problem. Ich hätte ja auch eine lahme Disk als Ursache vermutet, aber die Abfrage liest nichts von der Disk.

Ich glaube da hat das “obfuscation” von Depesz einen Fehler gemacht (ähnlich wie mit den Settings). Im Originalplan steht deutlich

Workers Planned: 4
Workers Launched: 4

und anders wäre (meiner Meinung nach) die Steigerung von 40 Sekunden auf 17 Sekunden ja auch nicht zu erklären, wenn sonst alles identisch ist.

Jetzt bin ich verwirrt. In der ersten Nachricht heißt es:

Auf dem Azure Server sehen wir aber im Execution Plan immer nur ein “Workers Planned: 1” und “Workers Launched: 1”

und jetzt sind es plötzlich 4. Oder ist das nicht der Plan von Azure? Den hätte ich nämlich gerne gesehen, weil der ja der problematische ist.

Du hast Recht. Es gibt zwei Abschnitte die mit “parallel workers” arbeiten.

Der entscheidende ist der Zweite bei dem 4 workers verwendet werden (bzw. eben nicht verwendet werden) auf den Du Dich beziehst..

Als ich den Plan erstellt habe, gab es keine anderen Aktivitäten auf der Datenbank. Ich habe zusätzlich mal für eine Weile das System beobachtet und es gibt keine Prozesse mit backend_type = ‘parallel worker’

Es bleibt weiterhin die Frage offen, warum Azure sich strikt weigert das zu verwenden. Ich habe alle GUC die parallel oder worker oder concurrency im Namen enthalten verglichen, und die sind alle identisch.

Also, wenn ich das richtig verstehe: auf Azure werden 4 Worker geplant, aber nur einer läuft tatsächlich. Welche Version ist das denn?
Microsoft verweist in der Dokumentation nur auf PostgreSQL, was entweder heißen kann, daß es sich gleich verhält, oder, daß sie ihre Hacks in diesem Bereich nicht dokumentiert haben.

Patch 4291 ist derzeit „ready for committer” (Diskussion hier) — mit diesem Feature könnte man wenigstens loggen, wenn zu wenige Worker verfügbar sind. Das wäre hier interessant. Schreib doch auf den Thread, daß du das Feature gut brauchen könntest! Das hilft.

Wie sieht es eigentlich mit max_worker_processes aus? Vielleicht laufen da andere Hintergrundprozesse, die aber keine parallelen Hilfsprozesse sind? Steht irgendwas im Log?

Sonst bleibt nur, Microsoft zu fragen… Ja, hosted services haben durchaus ihre Nachteile.

Azure ist 18.1, lokal haben wir 18.2 - aber ich habe in den Release Notes nichts gefunden was das erklären könnte.

max_worker_processes ist auf beiden Systemen identisch konfiguriert (8). Auf die Postgres logs kann ich auf Azure nicht zugreifen. Da wir noch in der Testphase sind, wird das System nur von 1-2 Benutzern überhaupt verwendet (tatsächlich dürfte in unserem Testsystem derzeit mehr los sein).

Der Support Weg über Microsoft wird bereits beschritten. Mit dem Azure Hosting bin ich auch nicht glücklich, aber wenn der Kunde unbedingt die Kontrolle über seine sensiblen Daten abgeben will, kann ich ihm das nicht ausreden (zumal ich eh nur bei den Datenbankfragen an dem Projekt beteiligt bin)

Hallo,
ich bin da auch schon reingelaufen, du bildest dir das also nicht ein. Bei Azure Database for PostgreSQL Flexible Server wird Parallelität intern stark eingeschränkt, auch wenn die Parameter scheinbar korrekt gesetzt sind. Microsoft limitiert das bewusst auf der Managed-Plattform, damit einzelne Kunden nicht zu viele Ressourcen ziehen. Deshalb bleibt der Planner extrem vorsichtig und startet oft nur einen Worker, selbst bei 8 vCPU. Bei uns war das Verhalten nie identisch zu einer normalen Ubuntu-VM. Am Ende blieb nur: damit leben oder PostgreSQL selbst auf einer VM betreiben, wenn Parallelisierung wirklich wichtig ist.

Ich sehe auch das hier:

Nested Loop Left Join  (...) (actual time=46122.498..46122.499 rows=0.00 loops=1)
  Inner Unique: true
  Filter: (((uniform_zulu1.romeo_papa)::text ~~* 'yankee_golf'::text) OR
           ((lima_victor1.whiskey_juliet)::text ~~* 'yankee_golf'::text))
  Rows Removed by Filter: 14374775

Das schaut aus, als wäre das so eine Abfrage:

SELECT ...
FROM a JOIN b ON ...
WHERE a.col1 ILIKE 'something'
   OR b.col2 ILIKE 'something'

Das kann PostgreSQL nicht anders lösen, als die 14 Millionen Zeilen des Joins auszurechnen und dann alle durch den Filter zu eliminieren.

Wenn es einen Trigram-Index auf beiden Spalten gibt, könnte man das vielleicht effizienter so umschreiben:

SELECT ...
FROM a JOIN b ON ...
WHERE a.col1 ILIKE 'something'
UNION
SELECT ...
FROM a JOIN b ON ...
WHERE b.col2 ILIKE 'something'

Das schaut zwar komplizierter aus, könnte aber (wenn man die nötigen Indexe für den Join hat) mit zwei kleinen Nested Loop-Joins schnell erledigt sein.

Ja, da ist ein trigram index drauf. Das ist ja schon ein großes UNION um OR Bedingungen genauso aufzulösen. Das Umschreiben in weiter “unter” UNIONS wird deutlich komplizierter. Das schaue ich mir tatsächlich gerade an :slight_smile:

Das ist - meiner Meinung nach - eine Spam Antwort generiert von einem KI Bot um dem Spam-Link den Anschein von Seriosität zu geben

1 „Gefällt mir“