PostgreSQL 17/18: 新機能とパフォーマンスの向上
PostgreSQL は依然として世界で最も先進的なオープンソース リレーショナル データベースであり、バージョン 17 と 18 は統合されています。
このポジションには、生産パフォーマンスに直接影響を与える大幅な改善が加えられています。
2024 年 9 月 26 日にリリースされた PostgreSQL 17 は、増分 VACUUM、SQL/JSON を提供します。 JSON_TABLE()
そして賢いプランナー。 2025 年 9 月にリリースされた PostgreSQL 18 では、ネイティブの非同期 I/O が追加されています。
仮想生成列と OAuth 2.0: 最新のアプリケーションの世代の飛躍。
何を学ぶか
- クエリとメンテナンスを改善する PostgreSQL 17 の主な機能
- PostgreSQL 18 非同期 I/O が集中的なワークロードに及ぼす影響
- 使用方法
JSON_TABLE()半構造化データに対するクエリを簡素化するため - 実際のベンチマーク: アップグレード後、パフォーマンスはどの程度向上しますか?
- PostgreSQL 16 から 17/18 にアップグレードするための実践的なガイド
PostgreSQL 17: 最も影響力のあるニュース
バージョン 17 は、メモリとストレージの管理、SQL/JSON、プランナーのパフォーマンスの 3 つの領域に焦点を当てています。 生産に最も大きな影響を与えるイノベーションを見てみましょう。
インクリメンタルバキューム
従来の VACUUM はテーブル全体をスキャンします。 PostgreSQL 17 の増分 VACUUM を使用すると、 プロセスは構成可能な「チャンク」で動作し、ロックの競合とピーク I/O を削減します。 これは、従来の VACUUM がパフォーマンスの低下を引き起こした大規模なテーブルにとって非常に重要です。 ユーザーに表示されます。
-- 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;
JSON_TABLE() を使用した SQL/JSON
JSON_TABLE() そして最も待ち望まれていた SQL ニュース: を使用せずに JSON をリレーショナル行に変換する
機能 jsonb_to_recordset() または複雑な表現。 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() 単に構文がきれいになっただけではありません。プランナーは構文をより適切に最適化できます。
横方向の結合と機能に基づいた 17 年以前のアプローチよりも効率的な計画を生成します。
クエリプランナーの改善
PostgreSQL 17 には、範囲スキャンの選択性推定に対する大幅な改善が含まれています。
~の推定コストの削減 DISTINCT インデックスのある列での使用と最適な使用法
の存在下での B ツリー インデックスの 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: 非同期 I/O への飛躍
PostgreSQL 18 では、アーキテクチャ上の最も大きな変更の 1 つであるネイティブ非同期 I/O が導入されています。
近年の。歴史的には、PostgreSQL が使用されていました。 pread() 同期: すべての操作
読み取りにより、完了するまでプロセスがブロックされました。非同期 I/O により、より多くの操作が可能
読み取りを同時に開始できるため、最新の 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 互換性
io_uring Linux カーネル 5.1 以降が必要です。古いカーネルを搭載したシステムまたは macOS/Windows では、
PostgreSQL 18 は自動的にフォールバックします。 io_method = workerただし、改善されます
従来の同期と比較したスループットの向上。
仮想生成列
PostgreSQL 17 には、 保管されている 生成された列 (計算されてディスクに保存された値)。 PostgreSQL 18 では、 バーチャル 生成された列: 値はその場で計算されます ディスクスペースを占有せずに読み取ります。光の変化に最適です。
-- 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;
OAuth 2.0認証
PostgreSQL 18 は、認証方法として OAuth 2.0 をネイティブにサポートしているため、OAuth 2.0 の必要性がなくなりました。
企業 ID プロバイダー (Azure AD、Okta、Google) と統合するための外部プロキシまたはラッパー
ワークスペース)。構成は次の場所で行われます 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"
実際のベンチマーク: パフォーマンスはどの程度向上しますか?
公式 PostgreSQL ベンチマークとコミュニティ テストでは大幅な改善が示されています 実際のシナリオでは。これらの結果は、一般的な製品ハードウェアで得られたものです。 8コアCPU、32GB RAM、NVMe SSD。
| シナリオ | PostgreSQL 16 | PostgreSQL 17 | PostgreSQL 18 |
|---|---|---|---|
| 30% のデッドタプルを含む 50GB テーブルでの VACUUM | 480年代 | 310秒 (-35%) | 280秒 (-42%) |
| シーケンシャルスキャン 100M ライン (NVMe) | 28秒 | 25秒 (-11%) | 17秒 (-39%) |
| 1M JSON ドキュメントの JSON_TABLE() | 該当なし | 4.2秒 | 3.1秒 |
| pgbench TPS (スケール = 1000、クライアント = 50) | 18,400 | 19,100 (+3.8%) | 21,800 (+18.5%) |
アップグレード ガイド: PostgreSQL 16 から 17/18 へ
PostgreSQL 17/18 へのアップグレードは、次のようにして実行できます。 pg_upgrade (インプレースアップグレード、より高速)
または論理レプリケーション経由 (ダウンタイムなしでアップグレード)。両方のアプローチを見てみましょう。
pg_upgrade によるアップグレード (簡単な方法)
#!/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
論理レプリケーションによるダウンタイムゼロのアップグレード
-- 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');
アップグレードのベスト プラクティス
- 常に実行する
pg_upgrade --check実際のアップグレード前に非互換性を検出する - カットオーバーの前に、実稼働データベースのクローンでアップグレードをテストします。
- Con
--linkアップグレードはほぼ瞬時に行われますが、 ロールバックしないでください PG17の最初のスタート後 - アップグレード後に拡張機能を更新します。
ALTER EXTENSION nome UPDATE - アップグレード後 1 週間は遅いクエリを監視します。プランナーは計画を変更できます。
開発者向けニュース: SQL の改善
PostgreSQL 17 および 18 は、パフォーマンスに加えて、SQL を簡素化するためのいくつかの新機能をもたらします。 日々の発展。
RETURNING を使用した MERGE (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;
ON_ERROR を伴う COPY FROM (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;
PostgreSQL 17/18 の最適な構成
アップグレードのたびに、構成を見直す機会が得られます。これらのパラメータは特に、 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
アップグレード後のモニタリング
アップグレード後、少なくとも 1 週間は次の指標を積極的に監視してください。
-- 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;
結論
PostgreSQL 17 および 18 は、ハードウェアを最大限に活用したい人にとって必須のアップグレードです。
インクリメンタル VACUUM は、大きなテーブルに関する過去の問題の 1 つを解決します。 JSON_TABLE()
半構造化データのクエリを簡素化し、PG18 の非同期 I/O により改善がもたらされます。
NVMe を使用すると、I/O バウンドのワークロードで最大 40% のスループットを実現します。
シリーズの次の記事では、クエリ プランを読み取り、最適化する方法について詳しく説明します。
EXPLAIN ANALYZE: 本番環境で遅いクエリを特定するための最も強力な手法。
シリーズ: データベースのエンジニアリングと最適化
- 第1条(本): PostgreSQL 17/18 - 新機能とパフォーマンス
- 記事 2: EXPLAIN ANALYZE - クエリ プランの読み取りと最適化
- 第 3 条: 高度なインデックス作成 - 部分、カバリング、BRIN、GIN
- 第 4 条: テーブルのパーティショニング - 数十億行の管理
- 記事 5: 接続プーリング - PgBouncer と Pgpool-II







