Prestandaoptimering och frågeoptimering i PostgreSQL · Lektion

Parallell aggregering och hash-joiner

Utnyttja partiella aggregat och parallellmedvetna joiner för tunga grupperingsarbetsbelastningar.

Lektion 3 av 413 steg

Parallell aggregering och hash-joiner är en gratis lektion i Prestandaoptimering och frågeoptimering i PostgreSQL på CoddyKit. Detta är lektion 3 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Prestandaoptimering och frågeoptimering i PostgreSQL, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Prestandaoptimering och frågeoptimering i PostgreSQL innehåller totalt 4 lektioner.

Varför parallellism för aggregering

Tunga grupperingsfrågor som GROUP BY över hundratals miljoner rader är vanligtvis CPU-bundna: det mesta av tiden går åt till att beräkna hashvärden för nycklar och kombinera värden, inte till att vänta på I/O.

En enda backend-process kan bara mätta en kärna. PostgreSQLs mekanism för parallella frågor låter planeraren dela upp skanningen och aggregeringen på flera parallella arbetare, som var och en kör på sin egen kärna, och sedan kombinera resultaten.

  • Backend-processen som startar körningen är ledaren.
  • De extra processerna är parallella arbetare.
  • Arbetet delas upp på tabellskanningsnivå och slås samman högst upp.

Den här lektionen fokuserar på två delar som samarbetar: parallell aggregering (partiella aggregat) och hash-joiner med parallellitetsstöd.

Partiellt och slutligt aggregat

Parallell aggregering fungerar genom att varje aggregering delas upp i två faser:

  • Partial Aggregate — varje workerprocess aggregerar sitt eget utsnitt av rader till ett delresultat (till exempel en löpande summa och ett antal).
  • Finalize Aggregate — ledarprocessen kombinerar delresultaten till det slutliga resultatet.

Detta är möjligt eftersom aggregeringar som count, sum, avg, min och max är kombinerbara: ett delresultat från en workerprocess kan slås ihop med ett annat via en kombinationsfunktion.

I planerna visas detta som en Partial Aggregate-nod under Gather och en Finalize Aggregate-nod ovanför den.

Läsa en plan för parallell aggregering

Kör EXPLAIN på en stor grupperad fråga och leta efter sandwichstrukturen Finalize / Gather / Partial. Noden Gather är där resultaten från workerprocesserna går tillbaka till ledarprocessen.

Observera Workers Planned: den parallellism som planeraren har avsett. Vid körning rapporterar EXPLAIN ANALYZE även Workers Launched, vilket kan vara lägre om systemet har slut på workerplatser.

EXPLAIN (COSTS OFF)
SELECT customer_id, sum(amount) AS total
FROM orders
GROUP BY customer_id;

-- Finalize HashAggregate
--   Group Key: customer_id
--   -> Gather
--        Workers Planned: 4
--        -> Partial HashAggregate
--             Group Key: customer_id
--             -> Parallel Seq Scan on orders

Inställningar som styr parallellism

Planeraren överväger bara parallella planer när vissa GUC:er tillåter det och när tabellen är tillräckligt stor för att det ska löna sig.

  • max_parallel_workers_per_gather — maximalt antal workerprocesser som en enskild Gather får använda (0 inaktiverar parallella frågor för den noden).
  • max_parallel_workers — gräns för hela instansen.
  • max_worker_processes — en hård gräns på operativsystemnivå för alla bakgrundsworkerprocesser.
  • min_parallel_table_scan_size (standardvärde 8MB) — tabellen måste vara större än detta för att en parallell genomsökning ska övervägas.
  • parallel_setup_cost och parallel_tuple_cost — modellerar kostnaden för att starta workerprocesser och skicka tupler.
SET max_parallel_workers_per_gather = 4;
SET max_parallel_workers = 8;

SHOW min_parallel_table_scan_size;   -- 8MB default
SHOW parallel_setup_cost;            -- 1000 default

Tvinga fram parallellism för experiment

På små testtabeller kan planeraren bedöma att parallellismens startkostnad inte lönar sig. För att studera planer kan du kraftigt styra planeraren mot parallellism och sedan mäta på realistiska data.

Om du sätter parallel_setup_cost och parallel_tuple_cost till 0 ignorerar planeraren startkostnaden för workerprocesser, så att den väljer parallella planer även för måttligt stora indata. Detta är ett diagnostiskt knep, inte en inställning för produktion.

SET parallel_setup_cost = 0;
SET parallel_tuple_cost = 0;
SET min_parallel_table_scan_size = '0';
SET max_parallel_workers_per_gather = 4;

EXPLAIN (ANALYZE, COSTS OFF)
SELECT region, count(*)
FROM sales
GROUP BY region;

Parallellmedveten hash-join

En Hash Join bygger en hash-tabell i minnet från den mindre sidan (byggsidan) och slår sedan upp rader från den större sidan i den. I en Parallel Hash Join är själva join-operationen parallellmedveten.

  • Plannoden är Parallel Hash Join med en inre nod av typen Parallel Hash.
  • Alla workerprocesser samarbetar för att bygga en gemensam hash-tabell i dynamiskt delat minne.
  • Därefter slår varje workerprocess upp sin del av den yttre relationen i den gemensamma tabellen.

Detta gör att varje workerprocess slipper bygga en egen privat kopia av hash-tabellen, vilket sparar både CPU och minne.

EXPLAIN (COSTS OFF)
SELECT o.customer_id, sum(o.amount)
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE c.country = 'DE'
GROUP BY o.customer_id;

-- Finalize GroupAggregate
--   -> Gather
--        -> Partial HashAggregate
--             -> Parallel Hash Join
--                  Hash Cond: (o.customer_id = c.id)
--                  -> Parallel Seq Scan on orders o
--                  -> Parallel Hash
--                       -> Parallel Seq Scan on customers c

Gemensam hash jämfört med hash per worker

Var noga med att skilja mellan två planer som ytligt sett liknar varandra:

  • Parallel Hash Join (med Parallel Hash): workerprocesserna bygger tillsammans en gemensam hash-tabell. Byggkostnaden och minnet delas.
  • Hash Join under Gather (vanlig Hash): varje workerprocess bygger sin egen fullständiga kopia av hash-tabellen. Byggarbetet och minnesåtgången multipliceras med antalet workerprocesser.

För en stor byggsida är den parallellmedvetna varianten mycket billigare. Planeraren väljer den när båda sidorna kan genomsökas parallellt och joinen är parallellsäker.

work_mem och hash-tabellen

Hash-joiner och hash-aggregeringar ryms inom work_mem. Om hash-tabellen inte får plats spiller PostgreSQL över till disk i batchar, vilket är mycket långsammare.

I EXPLAIN (ANALYZE, BUFFERS) ska du leta efter Batches: N där N > 1 och Disk Usage på hash-noder — tecken på att work_mem är för litet för byggsidan.

För Parallel Hash kan den gemensamma tabellen använda en större effektiv budget: workerprocessernas tilldelningar av work_mem slås ihop för den gemensamma hash-tabellen, vilket är ytterligare en anledning till att den parallellmedvetna joinen skalar bra.

SET work_mem = '256MB';

EXPLAIN (ANALYZE, BUFFERS, COSTS OFF)
SELECT o.product_id, count(*)
FROM orders o
JOIN products p ON p.id = o.product_id
GROUP BY o.product_id;

-- Look for: Parallel Hash  Batches: 1  Memory Usage: ...kB

Vad som inaktiverar parallellism

Planeraren avvisar parallella planer när frågan innehåller parallellosäkra element. Vanliga hinder är:

  • Anrop av en funktion som är märkt PARALLEL UNSAFE (standard för användardefinierade funktioner om du inte märker dem).
  • Skrivning av data: mål för INSERT, UPDATE och DELETE (den ändrande delen körs seriellt).
  • Markörer / radlåsning med FOR UPDATE i många fall.
  • max_parallel_workers_per_gather = 0.

Märk rena funktioner utan sidoeffekter som PARALLEL SAFE så att de inte blockerar parallella planer.

CREATE FUNCTION norm_region(txt text)
RETURNS text
LANGUAGE sql
IMMUTABLE
PARALLEL SAFE
AS $fn$ SELECT lower(trim(txt)) $fn$;

Ledarprocessens deltagande

Som standard utför ledarprocessen två uppgifter: den samlar både indata från workerprocesserna och hjälper till att köra den parallella planen. Detta styrs av parallel_leader_participation (standardvärde on).

För en fråga med N planerade workerprocesser är den effektiva parallellismen ungefär N+1 när ledarprocessen deltar. Men om ledarprocessen blir en flaskhals när den samlar in ett stort flöde av tupler kan det ibland hjälpa att stänga av deltagandet med off, så att workerprocesserna kan köra utan hinder — mät på båda sätten.

SET parallel_leader_participation = off;

EXPLAIN (ANALYZE, COSTS OFF)
SELECT category_id, avg(price)
FROM products
GROUP BY category_id;

Justera en tung grupperingsbelastning

Så här kan du gå tillväga för en CPU-bunden grupperad join:

  • Höj max_parallel_workers_per_gather så att planeraren kan dela upp genomsökningen (börja med antalet lediga kärnor).
  • Se till att max_parallel_workers och max_worker_processes är tillräckligt höga för att workerprocesserna faktiskt ska startas och inte begränsas.
  • Höj work_mem tills hash-noderna visar Batches: 1 (ingen spillning).
  • Kontrollera att planen visar Parallel Hash Join + Partial/Finalize Aggregate och att Workers Launched är lika med Workers Planned.

Verifiera alltid med EXPLAIN (ANALYZE, BUFFERS) på data i produktionsstorlek — kostnader i liten skala kan vara missvisande.

SET max_parallel_workers_per_gather = 6;
SET work_mem = '512MB';

EXPLAIN (ANALYZE, BUFFERS, COSTS OFF)
SELECT c.region, count(*) AS n, sum(o.amount) AS revenue
FROM orders o
JOIN customers c ON c.id = o.customer_id
GROUP BY c.region;

Snabbkontroll

Testa din förståelse av parallellmedvetna joiner.

Sammanfattning

Du har lärt dig hur PostgreSQL snabbar upp CPU-bundna grupperingsarbetsbelastningar:

  • Parallell aggregering delar upp arbetet i Partial Aggregate per workerprocess och Finalize Aggregate hos ledarprocessen, vilket är möjligt eftersom aggregeringar kan kombineras.
  • Parallel Hash Join bygger en gemensam hash-tabell över flera workerprocesser och undviker duplicering av byggkostnad och minne för varje workerprocess.
  • Sandwichstrukturen Finalize / Gather / Partial och noder av typen Parallel Hash visar hur du känner igen dessa planer i EXPLAIN.
  • Styr parallellismen med max_parallel_workers_per_gather, max_parallel_workers och trösklar för tabellstorlek; dimensionera hash-tabeller med work_mem för att undvika spillning till disk.
  • Parallellosäkra funktioner och satser som ändrar data inaktiverar parallella planer; märk rena funktioner som PARALLEL SAFE.

Kontrollera alltid att Workers Launched överensstämmer med Workers Planned och verifiera med EXPLAIN (ANALYZE, BUFFERS) på verkliga data.

Gratis att börja

Lär dig SQL med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
22
Lektioner
88

Vanliga frågor

Är lektionen ”Parallell aggregering och hash-joiner” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Prestandaoptimering och frågeoptimering i PostgreSQL, inklusive ”Parallell aggregering och hash-joiner”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Prestandaoptimering och frågeoptimering i PostgreSQL innehåller totalt 4 lektioner.

Vad lär jag mig i ”Parallell aggregering och hash-joiner”?

Utnyttja partiella aggregat och parallellmedvetna joiner för tunga grupperingsarbetsbelastningar. Ni övar på Prestandaoptimering och frågeoptimering i PostgreSQL med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Prestandaoptimering och frågeoptimering i PostgreSQL?

Du behöver inga förkunskaper. Utbildningen i Prestandaoptimering och frågeoptimering i PostgreSQL på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Parallell aggregering och hash-joiner”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Prestandaoptimering och frågeoptimering i PostgreSQL-lektionen?

Ja. Varje Prestandaoptimering och frågeoptimering i PostgreSQL-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. När planeraren väljer parallella planer
  2. Finjustera arbetarantal och Gather-kostnader
  3. Parallell aggregering och hash-joiner
  4. Diagnostisera varför parallellism inaktiverades
← Tillbaka till Prestandaoptimering och frågeoptimering i PostgreSQL