PostgreSQL Performance & Query Optimization · Lezione

Ottimizzazione del fillfactor per tabelle soggette a molti update

Imposti fillfactor lasciando spazio per gli aggiornamenti HOT e riducendo il churn degli indici sulle righe modificate di frequente.

Lezione 3 di 413 passaggi

Ottimizzazione del fillfactor per tabelle soggette a molti update è una lezione PostgreSQL Performance & Query Optimization gratuita su CoddyKit. Questa è la lezione 3 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é gli aggiornamenti sono costosi in PostgreSQL

PostgreSQL utilizza MVCC: un UPDATE non sovrascrive mai una riga direttamente. Scrive invece una versione completamente nuova della riga (tupla) e contrassegna quella precedente come morta.

  • La nuova tupla deve essere collocata da qualche parte sul disco.
  • Se finisce su una pagina diversa rispetto alla versione precedente, ogni indice della tabella deve essere aggiornato per puntare alla nuova posizione.

Nelle tabelle soggette a molti aggiornamenti, questo ricambio degli indici diventa una fonte rilevante di amplificazione delle scritture e bloat. La lezione di oggi spiega come fillfactor aiuta a evitarlo.

Che cosa controlla realmente fillfactor

fillfactor è un parametro di archiviazione per tabella (e per indice), espresso come percentuale da 10 a 100.

  • Indica a PostgreSQL quanto riempire ogni pagina da 8 KB quando inserisce le righe.
  • Un fillfactor pari a 100 (il valore predefinito per le tabelle) riempie completamente le pagine.
  • Un fillfactor pari a 90 lascia circa il 10% di ogni pagina come spazio libero riservato agli aggiornamenti futuri.

Questo spazio riservato è fondamentale per consentire aggiornamenti meno costosi sulla stessa pagina.

ALTER TABLE orders SET (fillfactor = 90);

Aggiornamenti HOT: il vantaggio

Un aggiornamento HOT (Heap-Only Tuple) si verifica quando:

  • nessuna delle colonne aggiornate fa parte di un indice; e
  • la nuova tupla entra nella stessa pagina di quella precedente.

Quando entrambe le condizioni sono soddisfatte, PostgreSQL collega la nuova versione a quella precedente all'interno della pagina e non aggiorna affatto gli indici. Non si verifica alcun ricambio degli indici, il WAL è molto più contenuto e la versione precedente può essere ripulita in modo efficiente dall'HOT pruning.

Lasciare spazio libero tramite un fillfactor più basso rende possibile soddisfare la condizione della "stessa pagina".

Impostare fillfactor su una nuova tabella

È possibile dichiarare il parametro di archiviazione al momento di CREATE TABLE. È l'approccio più pulito, perché la tabella viene organizzata correttamente fin dal primo inserimento.

  • Scelga un valore che riservi spazio sufficiente per il numero tipico di versioni delle righe nella pagina tra un vacuum e l'altro.
  • 90 è un punto di partenza comune; 70–80 è adatto alle righe soggette a modifiche molto frequenti.
CREATE TABLE session_state (
    session_id   uuid PRIMARY KEY,
    last_seen_at timestamptz NOT NULL,
    hit_count    integer NOT NULL DEFAULT 0,
    payload      jsonb
) WITH (fillfactor = 80);

Modificare fillfactor su una tabella esistente

ALTER TABLE ... SET (fillfactor = N) modifica il parametro, ma non riscrive le pagine esistenti. Solo le pagine scritte successivamente rispettano il nuovo valore.

Per applicarlo ai dati esistenti, riscriva la tabella con VACUUM FULL o CLUSTER (entrambi acquisiscono un lock ACCESS EXCLUSIVE), oppure utilizzi pg_repack per una riscrittura online.

ALTER TABLE session_state SET (fillfactor = 80);
VACUUM FULL session_state;

Confermare che si è verificato un aggiornamento HOT

Non deve procedere per supposizioni. pg_stat_user_tables espone contatori che indicano se gli aggiornamenti seguono il percorso HOT.

  • n_tup_upd — totale delle tuple aggiornate;
  • n_tup_hot_upd — numero di aggiornamenti HOT tra questi.

Un rapporto elevato tra n_tup_hot_upd / n_tup_upd indica che fillfactor e la progettazione degli indici stanno dando risultati.

SELECT relname,
       n_tup_upd,
       n_tup_hot_upd,
       round(100.0 * n_tup_hot_upd / NULLIF(n_tup_upd, 0), 1) AS hot_pct
FROM pg_stat_user_tables
WHERE relname = 'session_state';

Le colonne indicizzate impediscono gli aggiornamenti HOT

Lo spazio libero da solo non basta. Se un UPDATE interessa una qualsiasi colonna indicizzata, PostgreSQL deve creare una nuova voce nell'indice; l'aggiornamento non può quindi essere HOT, anche se la nuova tupla entra nella stessa pagina.

  • Mantenga, quando possibile, le colonne aggiornate frequentemente (contatori, timestamp, flag di stato) fuori dagli indici.
  • Elimini gli indici che non sono realmente necessari: ciascuno può impedire gli aggiornamenti HOT.

Esempio: indicizzare hit_count vanificherebbe l'intero scopo della configurazione di fillfactor per questa tabella.

-- This index would block HOT updates whenever hit_count changes:
-- CREATE INDEX ON session_state (hit_count);

-- Prefer indexing stable columns instead:
CREATE INDEX idx_session_last_seen ON session_state (last_seen_at);

Scegliere un valore: il compromesso

Un fillfactor più basso non è privo di costi. I compromessi sono:

  • Fillfactor più basso → più spazio libero per pagina → più aggiornamenti HOT e meno ricambio degli indici → ma la tabella occupa più pagine, quindi le scansioni sequenziali e la cache dei buffer contengono meno righe per pagina.
  • Fillfactor più alto → archiviazione più densa e migliore efficienza di scansione e cache → ma gli aggiornamenti si spostano su nuove pagine, causando ricambio degli indici e bloat.

Regola generale: mantenga 100 per le tabelle in cui si inseriscono dati in coda o che sono utilizzate principalmente in lettura; scenda a 70–90 solo per le tabelle realmente soggette a molti aggiornamenti.

Anche fillfactor sugli indici

Gli indici hanno un proprio fillfactor (il valore predefinito è 90 per gli alberi B). Ridurlo lascia spazio nelle pagine foglia, così le nuove voci non causano frequenti suddivisioni delle pagine nelle tabelle con molti inserimenti di chiavi monotonamente crescenti.

  • Per chiavi append-only o sempre crescenti, il valore predefinito è generalmente adeguato.
  • Per gli indici su chiavi distribuite casualmente e soggette a frequenti modifiche, un fillfactor dell'indice leggermente più basso può ridurre le suddivisioni.
CREATE INDEX idx_session_last_seen
    ON session_state (last_seen_at)
    WITH (fillfactor = 80);

Analisi delle impostazioni correnti

Per verificare se una tabella ha già un fillfactor diverso da quello predefinito, legga reloptions da pg_class. Un valore NULL indica che è attivo il valore predefinito (100 per l'heap, 90 per gli alberi B).

SELECT relname, reloptions
FROM pg_class
WHERE relname IN ('session_state', 'idx_session_last_seen');

Un flusso di ottimizzazione pratico

Riunendo tutti gli elementi per una tabella soggetta a molti aggiornamenti:

  • 1. Confermi che il carico di lavoro sia dominato dagli aggiornamenti e controlli il rapporto corrente di n_tup_hot_upd.
  • 2. Sposti le colonne soggette a frequenti modifiche fuori dagli indici; elimini gli indici inutilizzati.
  • 3. Imposti il fillfactor (iniziando da 90 e riducendolo verso 70 se il rapporto HOT è ancora basso).
  • 4. Riscriva la tabella (VACUUM FULL / CLUSTER / pg_repack) affinché le pagine esistenti vengano ricreate con il nuovo impacchettamento.
  • 5. Misuri nuovamente il rapporto HOT e apporti le modifiche necessarie.

Convalidi sempre i risultati tramite la vista delle statistiche: non ottimizzi alla cieca.

ALTER TABLE session_state SET (fillfactor = 75);
CLUSTER session_state USING idx_session_last_seen;
ANALYZE session_state;

Verifica rapida

Ha una tabella soggetta a molti aggiornamenti, la cui colonna status cambia continuamente, e ha ridotto fillfactor a 80, ma n_tup_hot_upd rimane vicino a zero. Qual è la causa più probabile?

Riepilogo

Concetti fondamentali per ottimizzare fillfactor nelle tabelle soggette a molti aggiornamenti:

  • fillfactor riserva spazio libero in ogni pagina, così le righe aggiornate possono rimanere nella stessa pagina, abilitando gli aggiornamenti HOT.
  • Gli aggiornamenti HOT saltano la manutenzione degli indici, riducendo la write amplification e il bloat.
  • HOT richiede sia spazio nella stessa pagina sia che nessuna colonna indicizzata venga modificata; pertanto, mantenga le colonne soggette a frequenti modifiche fuori dagli indici.
  • ALTER TABLE SET (fillfactor=N) influisce solo sulle nuove pagine; usi VACUUM FULL/CLUSTER/pg_repack per applicarlo ai dati esistenti.
  • Misuri il risultato con n_tup_hot_upd / n_tup_upd in pg_stat_user_tables e ottimizzi iterativamente.
  • Un fillfactor più basso sacrifica la densità di archiviazione per ridurre il numero di aggiornamenti che devono essere spostati su nuove pagine: lo utilizzi solo quando il carico di lavoro lo giustifica.
Gratis per iniziare

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 fillfactor per tabelle soggette a molti update» è gratuita?

Sì — il testo completo di «Ottimizzazione del fillfactor per tabelle soggette a molti update» è 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 fillfactor per tabelle soggette a molti update»?

Imposti fillfactor lasciando spazio per gli aggiornamenti HOT e riducendo il churn degli indici sulle righe modificate di frequente. 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 3 di 4.

Quanto tempo richiede la lezione «Ottimizzazione del fillfactor per tabelle soggette a molti update»?

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

  1. Misurazione accurata della bloat di tabelle e indici
  2. Recupero dello spazio con pg_repack
  3. Ottimizzazione del fillfactor per tabelle soggette a molti update
  4. Internals di TOAST e memorizzazione dei valori di grandi dimensioni
← Torna a PostgreSQL Performance & Query Optimization