PostgreSQL 17/18: Ce este nou și îmbunătățiri ale performanței
PostgreSQL rămâne cea mai avansată bază de date relațională open-source din lume, iar versiunile 17 și 18 se consolidează
această poziție cu îmbunătățiri substanțiale care au un impact direct asupra performanței producției.
PostgreSQL 17, lansat pe 26 septembrie 2024, aduce VACUUM incremental, SQL/JSON cu JSON_TABLE()
și un planificator mai inteligent. PostgreSQL 18, lansat în septembrie 2025, adaugă I/O asincron nativ,
coloane generate virtual și OAuth 2.0: un salt generațional pentru aplicațiile moderne.
Ce vei învăța
- Caracteristici cheie în PostgreSQL 17 care îmbunătățesc interogările și întreținerea
- Impactul I/O asincron PostgreSQL 18 asupra sarcinilor de lucru intensive
- Cum se utilizează
JSON_TABLE()pentru a simplifica interogările pe date semi-structurate - Benchmark-uri reale: cât de mult se îmbunătățește performanța după upgrade?
- Ghid practic pentru actualizarea de la PostgreSQL 16 la 17/18
PostgreSQL 17: Cele mai impactante știri
Versiunea 17 se concentrează pe trei domenii: gestionarea memoriei și a stocării, SQL/JSON și performanța planificatorului. Să vedem inovațiile cu cel mai mare impact în producție.
VACUUM incremental
Tradiționalul VACUUM scanează întreaga masă. Cu PostgreSQL 17 incremental VACUUM, procesul funcționează în „bucăți” configurabile, reducând conflictul de blocare și I/O de vârf. Acest lucru este esențial pentru mesele mari unde VACUUM tradițional a cauzat degradarea vizibil pentru utilizatori.
-- PostgreSQL 17: configurare l'incremental vacuum
ALTER TABLE ordini SET (
vacuum_max_eager_freeze_failure_rate = 0.03
);
-- Monitorare l'attivita del vacuum
SELECT
schemaname,
tablename,
last_vacuum,
last_autovacuum,
n_dead_tup,
n_live_tup,
n_mod_since_analyze
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;
SQL/JSON cu JSON_TABLE()
JSON_TABLE() și cele mai așteptate știri SQL: transformă JSON în rânduri relaționale fără a folosi
funcții jsonb_to_recordset() sau expresii complexe. Compatibil cu standardul SQL/JSON
ISO/IEC 9075-2:2023.
-- Prima (PostgreSQL 16): approccio con jsonb_to_recordset
SELECT
evento->>'tipo' AS tipo,
evento->>'utente_id' AS utente_id,
(evento->>'timestamp')::timestamptz AS ts
FROM log_eventi,
jsonb_array_elements(payload->'eventi') AS evento;
-- Dopo (PostgreSQL 17): JSON_TABLE() standard ISO
SELECT jt.*
FROM log_eventi,
JSON_TABLE(
payload,
'$.eventi[*]' COLUMNS (
tipo VARCHAR(50) PATH '$.tipo',
utente_id BIGINT PATH '$.utente_id',
ts TIMESTAMPTZ PATH '$.timestamp'
)
) AS jt;
JSON_TABLE() nu este doar o sintaxă mai curată: planificatorul o poate optimiza mai bine,
generând planuri mai eficiente decât abordările pre-17 bazate pe îmbinări laterale și funcții.
Îmbunătățiri ale Planificatorului de interogări
PostgreSQL 17 include îmbunătățiri semnificative ale estimării selectivității pentru scanările intervalului,
reducerea costului estimat pt DISTINCT pe coloane cu indici și cea mai bună utilizare
a indicilor B-Tree în prezenţa IS NULL e IS NOT NULL.
-- Verificare miglioramenti al planner con EXPLAIN
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT DISTINCT categoria_id
FROM prodotti
WHERE prezzo IS NOT NULL
AND disponibile = true;
-- PostgreSQL 17 usa meglio gli indici composti in questi scenari
CREATE INDEX CONCURRENTLY idx_prodotti_cat_prezzo
ON prodotti (categoria_id, prezzo)
WHERE disponibile = true;
PostgreSQL 18: Saltul la I/O asincron
PostgreSQL 18 introduce I/O asincron nativ, una dintre cele mai profunde schimbări arhitecturale
din ultimii ani. Din punct de vedere istoric, PostgreSQL a folosit pread() sincron: fiecare operație
citirea a blocat procesul până la finalizare. Cu I/O asincron, mai multe operațiuni
citirea poate fi începută simultan, utilizând mai bine hardware-ul modern NVMe.
-- postgresql.conf: nuovi parametri per l'I/O asincrono in PG18
# Abilitare il backend I/O asincrono (default: io_uring su Linux 5.1+)
io_method = io_uring # oppure 'worker' per compatibilita
# Numero massimo di richieste I/O asincrone in volo
io_max_concurrency = 32 # da aumentare per NVMe ad alte IOPS
# Dimensione della coda I/O per worker
io_workers = 4 # worker thread per operazioni I/O
io_uring compatibilitate
io_uring necesită Linux kernel 5.1+. Pe sistemele cu nuclee mai vechi sau pe macOS/Windows,
PostgreSQL 18 efectuează o rezervă automată la io_method = worker, care însă se îmbunătățește
debitul comparativ cu sincronul tradițional.
Coloane generate virtuale
PostgreSQL 17 avea stocate coloane generate (valoare calculată și salvată pe disc). PostgreSQL 18 adaugă virtual coloane generate: valoarea se calculează pe loc citind, fără a ocupa spațiu pe disc. Ideal pentru transformări luminoase.
-- PostgreSQL 18: virtual generated column (non salvata su disco)
CREATE TABLE prodotti (
id BIGSERIAL PRIMARY KEY,
nome TEXT NOT NULL,
prezzo_netto NUMERIC(10,2) NOT NULL,
iva_pct NUMERIC(5,2) NOT NULL DEFAULT 22.0,
-- virtual: calcolata al volo, 0 spazio su disco
prezzo_lordo NUMERIC(10,2) GENERATED ALWAYS AS
(ROUND(prezzo_netto * (1 + iva_pct / 100), 2)) VIRTUAL
);
-- La colonna e disponibile come le altre nelle query
SELECT nome, prezzo_netto, prezzo_lordo
FROM prodotti
WHERE prezzo_lordo BETWEEN 100 AND 500;
Autentificare OAuth 2.0
PostgreSQL 18 acceptă OAuth 2.0 nativ ca metodă de autentificare, eliminând necesitatea
de proxy-uri sau wrapper-uri externe pentru a se integra cu furnizorii de identitate corporativă (Azure AD, Okta, Google
Spațiul de lucru). Configurarea are loc în pg_hba.conf.
-- pg_hba.conf: autenticazione OAuth 2.0 (PostgreSQL 18)
# TYPE DATABASE USER ADDRESS METHOD OPTIONS
hostssl all app_user all oauth issuer="https://login.microsoftonline.com/tenant-id/v2.0"
scope="postgres"
Benchmarkuri reale: cât de mult se îmbunătățește performanța?
Benchmark-urile oficiale PostgreSQL și testarea comunității arată îmbunătățiri semnificative în scenarii reale. Aceste rezultate au fost obținute pe hardware de producție tipic: CPU cu 8 nuclee, 32 GB RAM, SSD NVMe.
| Scenariu | PostgreSQL 16 | PostgreSQL 17 | PostgreSQL 18 |
|---|---|---|---|
| VACUUM pe o masă de 50 GB cu 30% tuple moarte | 480 de ani | 310s (-35%) | 280s (-42%) |
| Scanare secvențială 100M de linii (NVMe) | 28s | 25 de secunde (-11%) | 17 secunde (-39%) |
| JSON_TABLE() pe 1 milion de documente JSON | N / A | 4,2s | 3.1s |
| pgbench TPS (scale=1000, client=50) | 18.400 | 19.100 (+3,8%) | 21.800 (+18,5%) |
Ghid de actualizare: de la PostgreSQL 16 la 17/18
Actualizarea la PostgreSQL 17/18 se poate face prin pg_upgrade (upgrade pe loc, mai rapid)
sau prin replicare logică (upgrade fără timp de nefuncționare). Să ne uităm la ambele abordări.
Faceți upgrade cu pg_upgrade (metoda rapidă)
#!/bin/bash
# Upgrade PostgreSQL 16 -> 17 con pg_upgrade
# 1. Installare PostgreSQL 17 (Ubuntu/Debian)
apt install postgresql-17
# 2. Fermare il cluster 16 (se non si usa --link)
systemctl stop postgresql@16-main
# 3. Eseguire pg_upgrade
/usr/lib/postgresql/17/bin/pg_upgrade \
--old-datadir /var/lib/postgresql/16/main \
--new-datadir /var/lib/postgresql/17/main \
--old-bindir /usr/lib/postgresql/16/bin \
--new-bindir /usr/lib/postgresql/17/bin \
--link \ # Hard link ai file dati: molto piu veloce (no copia)
--check # Prima: solo verifica, nessuna modifica
# 4. Se il check passa, eseguire l'upgrade reale (rimuovere --check)
/usr/lib/postgresql/17/bin/pg_upgrade \
--old-datadir /var/lib/postgresql/16/main \
--new-datadir /var/lib/postgresql/17/main \
--old-bindir /usr/lib/postgresql/16/bin \
--new-bindir /usr/lib/postgresql/17/bin \
--link
# 5. Avviare PostgreSQL 17
systemctl start postgresql@17-main
# 6. Eseguire analyze per aggiornare le statistiche
/usr/lib/postgresql/17/bin/vacuumdb --all --analyze-in-stages
Faceți upgrade cu Zero Downtime prin replicare logică
-- STEP 1: Sul server PostgreSQL 16 (source)
-- Configurare postgresql.conf
-- wal_level = logical (deve essere gia impostato)
-- max_replication_slots = 10
-- Creare la pubblicazione su tutte le tabelle
CREATE PUBLICATION pg17_migration FOR ALL TABLES;
-- STEP 2: Sul server PostgreSQL 17 (target)
-- Creare lo schema identico (migrare DDL)
-- ...
-- Creare la sottoscrizione
CREATE SUBSCRIPTION pg17_sub
CONNECTION 'host=pg16-host port=5432 dbname=mydb user=replicator'
PUBLICATION pg17_migration
WITH (create_slot = true, slot_name = 'pg17_migration_slot');
-- STEP 3: Monitorare la replica lag
SELECT
slot_name,
confirmed_flush_lsn,
pg_current_wal_lsn() - confirmed_flush_lsn AS lag_bytes
FROM pg_replication_slots;
-- STEP 4: Quando lag e vicino a zero, switchare il traffico
-- (aggiornare load balancer o DNS)
-- STEP 5: Cleanup dopo il cutover
DROP SUBSCRIPTION pg17_sub; -- su PG17
-- Sul PG16:
SELECT pg_drop_replication_slot('pg17_migration_slot');
Cele mai bune practici pentru upgrade-uri
- Execută întotdeauna
pg_upgrade --checkînainte de upgrade-ul propriu-zis pentru a detecta incompatibilitățile - Testați upgrade-ul pe o clonă a bazei de date de producție înainte de trecere
- Cu
--linkupgrade-ul este aproape instantaneu dar nu derulați înapoi după prima pornire a PG17 - Actualizați extensiile după actualizare:
ALTER EXTENSION nome UPDATE - Monitorizați interogările lente timp de o săptămână după actualizare: planificatorul poate schimba planurile
Noutăți pentru dezvoltatori: SQL îmbunătățit
Pe lângă performanță, PostgreSQL 17 și 18 aduc câteva funcții noi pentru a simplifica SQL dezvoltare zilnică.
MERGE cu RETURNING (PostgreSQL 17)
-- PostgreSQL 17: MERGE con RETURNING per upsert audit
MERGE INTO inventario AS target
USING (VALUES
(1001, 50, 'warehouse-A'),
(1002, 30, 'warehouse-B')
) AS source(prodotto_id, quantita, location)
ON target.prodotto_id = source.prodotto_id
WHEN MATCHED THEN
UPDATE SET
quantita = target.quantita + source.quantita,
ultimo_aggiornamento = NOW()
WHEN NOT MATCHED THEN
INSERT (prodotto_id, quantita, location, creato_il)
VALUES (source.prodotto_id, source.quantita, source.location, NOW())
RETURNING
prodotto_id,
xmax = 0 AS is_insert, -- true se INSERT, false se UPDATE
quantita;
COPY FROM cu ON_ERROR (PostgreSQL 17)
-- PostgreSQL 17: ignorare righe invalide durante COPY
-- Prima: l'intera operazione falliva alla prima riga corrotta
COPY prodotti (id, nome, prezzo)
FROM '/data/import.csv'
WITH (
FORMAT csv,
HEADER true,
ON_ERROR ignore, -- salta le righe con errori
LOG_VERBOSITY verbose -- logga le righe saltate
);
-- Verificare quante righe sono state saltate
SELECT count(*) FROM pg_temp.copy_summary;
Configurație optimă pentru PostgreSQL 17/18
Fiecare upgrade este o oportunitate de a revizui configurația. Acești parametri sunt în special relevante pentru știrile din PG17/18.
# postgresql.conf ottimizzato per PostgreSQL 18
# (hardware: 8 core, 32GB RAM, NVMe SSD)
# Memoria
shared_buffers = 8GB # 25% della RAM
effective_cache_size = 24GB # stima totale memoria disponibile
work_mem = 64MB # per sort/hash, attenzione a connessioni parallele
maintenance_work_mem = 2GB # per VACUUM, CREATE INDEX
# I/O asincrono (PostgreSQL 18)
io_method = io_uring # Linux 5.1+
io_max_concurrency = 64 # per NVMe ad alte IOPS
effective_io_concurrency = 200 # per bitmap heap scan
# Parallelismo
max_parallel_workers_per_gather = 4
max_parallel_workers = 8
max_parallel_maintenance_workers = 4
# Incremental VACUUM (PostgreSQL 17)
autovacuum_vacuum_cost_delay = 2ms # piu aggressivo (default: 2ms da PG17)
autovacuum_vacuum_cost_limit = 800 # aumentato da 200
# WAL
wal_level = logical # necessario per logical replication
max_wal_size = 4GB
checkpoint_completion_target = 0.9
Monitorizare post-upgrade
După actualizare, monitorizați în mod activ următorii indicatori timp de cel puțin o săptămână.
-- Query per identificare regressioni di performance post-upgrade
-- Richiede pg_stat_statements
SELECT
LEFT(query, 80) AS query_preview,
calls,
ROUND(mean_exec_time::numeric, 2) AS mean_ms,
ROUND(stddev_exec_time::numeric, 2) AS stddev_ms,
ROUND(total_exec_time::numeric, 0) AS total_ms,
rows / calls AS avg_rows
FROM pg_stat_statements
WHERE calls > 100
AND mean_exec_time > 100 -- query lente (>100ms)
ORDER BY mean_exec_time DESC
LIMIT 20;
-- Verificare se il planner cambia i piani rispetto a PG16
-- (abilitare auto_explain per catturare i piani)
LOAD 'auto_explain';
SET auto_explain.log_min_duration = '500ms';
SET auto_explain.log_analyze = true;
SET auto_explain.log_buffers = true;
Concluzii
PostgreSQL 17 și 18 sunt upgrade-uri obligatorii pentru cei care doresc să profite la maximum de hardware-ul lor.
VACUUM incremental rezolvă una dintre problemele istorice de pe mesele mari, JSON_TABLE()
simplifică interogările privind datele semi-structurate, iar I/O asincron al PG18 aduce îmbunătățiri
debit de până la 40% pentru sarcinile de lucru legate de I/O cu NVMe.
Următorul articol din serie analizează cum să citiți și să optimizați planurile de interogare
EXPLAIN ANALYZE: Cea mai puternică tehnică pentru identificarea interogărilor lente în producție.
Seria: Inginerie și optimizare a bazelor de date
- Articolul 1 (acest): PostgreSQL 17/18 - Ce este nou și performanță
- Articolul 2: EXPLICAȚI ANALIZA - Citiți și optimizați planurile de interogare
- Articolul 3: Indexare avansată - parțială, acoperire, BRIN, GIN
- Articolul 4: Partiționarea tabelelor - Gestionarea miliardelor de rânduri
- Articolul 5: Pooling de conexiuni - PgBouncer vs Pgpool-II







