Ottimizzazione del numero di worker e dei costi di Gather
Adatti le impostazioni dei worker paralleli e i costi per tupla, bilanciando l’accelerazione con l’overhead.
Ottimizzazione del numero di worker e dei costi di Gather è una lezione PostgreSQL Performance & Query Optimization gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento PostgreSQL Performance & Query Optimization, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso PostgreSQL Performance & Query Optimization include 4 lezioni in totale.
Perché le query parallele richiedono ottimizzazione
PostgreSQL può suddividere una singola query tra più core della CPU usando i parallel worker. Il processo leader avvia i worker di supporto, ognuno dei quali esegue la scansione di una porzione dei dati; i risultati vengono poi riuniti in un nodo Gather.
Il parallelismo non è gratuito. L'avvio dei worker, la copia delle tuple attraverso la memoria condivisa e la sincronizzazione nel punto di raccolta richiedono tutti tempo. Per insiemi di risultati piccoli, l'overhead può superare il guadagno di velocità.
- I carichi di lavoro CPU-bound (grandi scansioni sequenziali, aggregazioni, hash join) sono quelli che ne traggono maggior beneficio.
- Le query brevi sensibili alla latenza generalmente no.
Questa lezione illustra i parametri che determinano quanti worker vengono eseguiti e quando il planner ritiene che il parallelismo sia conveniente.
La struttura del piano: nodi Gather e Partial
Un piano parallelo ha una struttura caratteristica. Sotto il nodo Gather (o Gather Merge) si trovano le operazioni partial eseguite in parallelo dai worker; sopra di esso, tutto viene eseguito in modo seriale dal leader.
Legga il piano con EXPLAIN (ANALYZE, VERBOSE) e cerchi Workers Planned e Workers Launched. Una differenza tra i due valori indica che, al momento dell'esecuzione, il sistema ha esaurito gli slot worker disponibili.
EXPLAIN (ANALYZE, VERBOSE, BUFFERS)
SELECT count(*)
FROM orders
WHERE order_total > 100;
-- Look for:
-- Gather (cost=... rows=...)
-- Workers Planned: 2
-- Workers Launched: 2
-- -> Partial Aggregate
-- -> Parallel Seq Scan on ordersmax_parallel_workers_per_gather
Il parametro più importante per singola query è max_parallel_workers_per_gather. Stabilisce il numero massimo di worker che un singolo nodo Gather può richiedere. Il valore predefinito è 2.
Impostarlo a 0 disabilita completamente il parallelismo per quella sessione. Aumentarlo consente alle scansioni di grandi dimensioni di usare più core, ma solo entro i limiti imposti dalla dimensione della tabella e dagli altri parametri.
- È un limite per Gather, non per query. Una query con due nodi Gather può usare fino al doppio di questo numero di worker.
- Può essere modificato per sessione con
SET, così può ottimizzare un singolo report pesante senza modificare la configurazione globale.
-- Inspect current value
SHOW max_parallel_workers_per_gather;
-- Allow up to 4 workers per gather for this session
SET max_parallel_workers_per_gather = 4;
-- Disable parallelism for a latency-critical query
SET max_parallel_workers_per_gather = 0;Il budget dei worker su tre livelli
Il numero di worker è limitato da tre impostazioni annidate. Il numero effettivo di worker è il minimo tra tutti e tre i limiti e la stima basata sulla dimensione calcolata dal planner.
max_parallel_workers_per_gather— per nodo Gather (predefinito: 2).max_parallel_workers— pool a livello dell'intero cluster dedicato alle query parallele (predefinito: 8).max_worker_processes— numero totale di processi worker in background per l'intero server, condiviso con estensioni e replica (predefinito: 8).
Se aumenta il limite per Gather ma lascia basso max_parallel_workers, le query concorrenti entreranno in competizione e molte verranno eseguite con meno worker di quelli pianificati.
SHOW max_worker_processes; -- server-wide ceiling
SHOW max_parallel_workers; -- pool for parallel query
SHOW max_parallel_workers_per_gather; -- per-gather cap
-- A sane production starting point on an 8-core box:
-- max_worker_processes = 16
-- max_parallel_workers = 8
-- max_parallel_workers_per_gather = 4Come il planner sceglie il numero predefinito di worker
Anche con limiti elevati, il planner dimensiona il numero di worker in base alla dimensione della relazione, usando una regola logaritmica. Una tabella deve essere grande almeno quanto min_parallel_table_scan_size (predefinito: 8MB) prima che venga preso in considerazione anche un solo worker parallelo. In linea di massima, ogni aumento di 3× della dimensione aggiunge un worker.
- Da 8MB a 24MB, poi 72MB, poi 216MB... → 1, 2, 3... worker.
- Il risultato viene quindi limitato da
max_parallel_workers_per_gather.
Per questo una tabella molto piccola non viene mai elaborata in parallelo, indipendentemente da quanto aumenti i limiti, e a volte è necessario ridurre min_parallel_table_scan_size per testare i piani paralleli su dati di piccole dimensioni.
SHOW min_parallel_table_scan_size; -- default 8MB
SHOW min_parallel_index_scan_size; -- default 512kB
-- Force consideration of parallelism on smaller tables (testing)
SET min_parallel_table_scan_size = '0';parallel_setup_cost: l'overhead fisso
parallel_setup_cost rappresenta il costo una tantum dell'avvio dei worker e della configurazione della memoria condivisa. Il valore predefinito è 1000, un numero elevato nelle unità di costo del planner, scelto intenzionalmente affinché l'ottimizzatore eviti il parallelismo per le query poco costose.
Se il Suo hardware avvia rapidamente i worker e nota che piani paralleli validi vengono rifiutati, riducendo questo valore il planner sarà più propenso a usare il parallelismo. Lo aumenti per scoraggiare il parallelismo su un server OLTP molto carico.
SHOW parallel_setup_cost; -- default 1000
-- Make the planner more eager to go parallel
SET parallel_setup_cost = 200;
-- Then compare plans
EXPLAIN SELECT count(*) FROM orders WHERE shipped_at IS NULL;parallel_tuple_cost: il costo di raccolta per tupla
parallel_tuple_cost rappresenta il costo del trasferimento di ogni tupla da un worker al leader attraverso la coda di raccolta. Il valore predefinito è 0.1 per tupla.
Questo è il motivo principale per cui il parallelismo perde il vantaggio nelle query che restituiscono molte righe: ogni tupla restituita comporta un costo. I piani paralleli sono vantaggiosi quando i worker riducono i dati, filtrandoli in modo significativo o aggregandoli, così poche tuple attraversano il nodo Gather.
- Molte righe in uscita da Gather +
parallel_tuple_costelevato → il planner preferisce l'esecuzione seriale. - Lo riduca con cautela se il trasferimento delle tuple nella memoria condivisa è effettivamente poco costoso.
SHOW parallel_tuple_cost; -- default 0.1
-- A query that aggregates (few tuples cross Gather) loves parallelism;
-- a query that returns millions of raw rows pays parallel_tuple_cost on each.
EXPLAIN
SELECT customer_id, count(*)
FROM orders
GROUP BY customer_id; -- partial aggregate shrinks data before GatherOverride per tabella: il parametro di storage parallel_workers
Può fissare il numero di worker per una tabella specifica con il parametro di storage parallel_workers. Questo sostituisce la formula del planner basata sulla dimensione per le scansioni di quella tabella, pur restando soggetto ai limiti globali.
È utile per una tabella dei fatti molto utilizzata e sottoposta ad aggregazioni pesanti, quando desidera sempre, ad esempio, 6 worker indipendentemente dal valore predefinito calcolato con la regola logaritmica.
-- Pin parallel scans of this table to 6 workers
ALTER TABLE orders SET (parallel_workers = 6);
-- Remove the override, return to size-based defaults
ALTER TABLE orders RESET (parallel_workers);
-- Verify the setting
SELECT reloptions FROM pg_class WHERE relname = 'orders';Misurare il punto ottimale
L'ottimizzazione è empirica. Esegua la stessa query con numeri diversi di worker e confronti il tempo effettivo di esecuzione, non solo il costo del planner. Il guadagno di velocità è sublineare e alla fine si stabilizza o diminuisce con l'aumentare dell'overhead di coordinamento.
- Controlli
Workers Launched: se è inferiore aWorkers Planned, il pool è esaurito e aumentare il limite per Gather non sarà utile. - Rendimenti decrescenti: passare da 4 a 8 worker spesso offre un guadagno molto inferiore rispetto al passaggio da 1 a 2.
SET max_parallel_workers_per_gather = 2;
EXPLAIN (ANALYZE, TIMING OFF) SELECT count(*) FROM orders WHERE order_total > 100;
SET max_parallel_workers_per_gather = 4;
EXPLAIN (ANALYZE, TIMING OFF) SELECT count(*) FROM orders WHERE order_total > 100;
SET max_parallel_workers_per_gather = 8;
EXPLAIN (ANALYZE, TIMING OFF) SELECT count(*) FROM orders WHERE order_total > 100;Concorrenza: quando i worker si esauriscono
Il pool dei worker paralleli è condiviso dall'intero cluster. In condizioni di concorrenza, molte query pianificate con 4 worker ciascuna possono richiedere complessivamente più di quanto consentito da max_parallel_workers; di conseguenza, alcune vengono eseguite con un numero ridotto di worker o senza worker.
Nei sistemi con carichi OLTP elevati, questa è una caratteristica utile: si desidera che le transazioni brevi abbiano la priorità sulla CPU, invece di perderla a causa di una query di report che ha riservato 8 worker. Strategie:
- Mantenga
max_parallel_workers_per_gathersu valori moderati (2-4) a livello globale. - Lo aumenti per sessione solo per i job batch o di report noti.
- Si assicuri che
max_worker_processessia abbastanza alto da lasciare spazio anche a estensioni e replica.
Una procedura pratica di ottimizzazione
Riunendo tutti gli elementi per un carico di lavoro analitico CPU-bound su un server con 8 core:
- Impostare
max_worker_processes = 16(per lasciare margine alle estensioni). - Impostare
max_parallel_workers = 8(uno per core). - Mantenere globale
max_parallel_workers_per_gather = 2per proteggere la latenza OLTP. - Per le sessioni dei report notturni, usare
SET max_parallel_workers_per_gather = 6. - Ridurre
parallel_setup_cost/parallel_tuple_costsolo dopo che EXPLAIN ANALYZE ha dimostrato che piani validi vengono rifiutati.
Convalidi sempre i risultati con tempi reali e imposti valori per tabella solo per tabelle molto utilizzate, stabili e ben comprese.
-- Per-session profile for a heavy nightly aggregation job
SET max_parallel_workers_per_gather = 6;
SET parallel_setup_cost = 200;
SET min_parallel_table_scan_size = '4MB';
EXPLAIN (ANALYZE, BUFFERS)
SELECT region, date_trunc('day', created_at) AS d, sum(amount)
FROM sales
GROUP BY region, d;Verifica rapida: diagnosticare una carenza di worker
Esegue una query di aggregazione pesante. EXPLAIN ANALYZE mostra Workers Planned: 4, ma Workers Launched: 1, e l'esecuzione è appena più veloce di quella seriale. Quale singola modifica ha maggiori probabilità di risolvere la carenza?
Riepilogo: bilanciare guadagno di velocità e overhead
Ora dispone di un modello mentale per ottimizzare le query parallele:
- Il budget dei worker è stratificato: max_parallel_workers_per_gather ≤ max_parallel_workers ≤ max_worker_processes, con un'ulteriore riduzione in base alla dimensione della tabella.
- I costi determinano la scelta: parallel_setup_cost è il costo fisso di avvio; parallel_tuple_cost applica un costo a ogni tupla che attraversa Gather, quindi il parallelismo è vantaggioso quando i worker riducono i dati.
- È essenziale saper leggere il piano: confronti Workers Planned e Workers Launched per distinguere un problema di pianificazione da un problema del pool durante l'esecuzione.
- Ottimizzi per sessione, non globalmente, per proteggere la latenza OLTP consentendo ai job batch di usare i core.
Misuri con EXPLAIN ANALYZE e tempi reali; non si affidi mai soltanto al costo del planner.
Impara SQL con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 22
- Lezioni
- 88
Domande Frequenti
La lezione «Ottimizzazione del numero di worker e dei costi di Gather» è gratuita?
Sì — il testo completo di «Ottimizzazione del numero di worker e dei costi di Gather» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso PostgreSQL Performance & Query Optimization, passa a CoddyKit PRO. Il corso PostgreSQL Performance & Query Optimization include 4 lezioni in totale.
Cosa imparerò in «Ottimizzazione del numero di worker e dei costi di Gather»?
Adatti le impostazioni dei worker paralleli e i costi per tupla, bilanciando l’accelerazione con l’overhead. Eserciti PostgreSQL Performance & Query Optimization con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare PostgreSQL Performance & Query Optimization?
Non è richiesta alcuna esperienza precedente. PostgreSQL Performance & Query Optimization su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Ottimizzazione del numero di worker e dei costi di Gather»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione PostgreSQL Performance & Query Optimization?
Sì. Ogni lezione PostgreSQL Performance & Query Optimization include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Quando il planner sceglie piani paralleli
- Ottimizzazione del numero di worker e dei costi di Gather
- Aggregazioni parallele e hash join
- Diagnosi della disabilitazione del parallelismo