PostgreSQL 18 Deep Dive 2026 - Asynchronous I/O, Skip Scan, Virtual Generated Columns, UUIDv7 và OAuth 2.0: Cuộc Cách Mạng Hiệu Năng của OLTP Database Open-Source
Posted on: 4/15/2026 7:38:33 PM
Table of contents
- 1. PostgreSQL 18 - Một bản phát hành mang dáng dấp cách mạng
- 2. Từ PostgreSQL 15 đến PostgreSQL 18 - Bản đồ tiến hóa
- 3. Asynchronous I/O - Lớp nền tảng được viết lại
- 4. B-tree Skip Scan - Giải thoát khỏi giới hạn left-most prefix
- 5. Virtual Generated Columns - Mặc định mới
- 6. UUIDv7 - Kết thúc cuộc tranh cãi về primary key
- 7. OAuth 2.0 Authentication - Chia tay cơ chế password đơn thuần
- 8. RETURNING OLD/NEW - Audit trail viết lại gọn hơn
- 9. Temporal Constraints - WITHOUT OVERLAPS và PERIOD
- 10. pg_upgrade và bảo toàn thống kê planner
- 11. Logical Replication - Những cải tiến lặng lẽ nhưng quan trọng
- 12. Wire Protocol 3.2 - Cập nhật đầu tiên sau 22 năm
- 13. Observability - EXPLAIN và pg_stat_io nâng cấp
- 14. Unicode, casefold và tìm kiếm không phân biệt hoa thường
- 15. Checklist chuyển đổi PostgreSQL 17 → 18
- 16. Lời kết
- 17. Nguồn tham khảo
1. PostgreSQL 18 - Một bản phát hành mang dáng dấp cách mạng
Ngày 25 tháng 9 năm 2025, cộng đồng PostgreSQL chính thức phát hành PostgreSQL 18 - một trong những bản nâng cấp có sức nặng nhất kể từ khi MVCC được hoàn thiện. Nếu PostgreSQL 16 là bản "tinh chỉnh trưởng thành" và PostgreSQL 17 là bản "nâng cấp công cụ vận hành", thì PostgreSQL 18 chính là bản viết lại lớp I/O - nơi sâu nhất và nhạy cảm nhất của một cơ sở dữ liệu quan hệ.
Trong suốt hai thập kỷ, PostgreSQL luôn dựa trên mô hình đọc ghi đồng bộ: tiến trình backend gọi read(), kernel chặn tiến trình đó cho đến khi trả dữ liệu về, rồi mới xử lý tiếp. Mô hình này đơn giản, dễ hiểu và an toàn, nhưng bỏ phí hiệu năng đáng kể trên phần cứng hiện đại như NVMe SSD, PCIe 5.0 hay NVMe-over-Fabrics. PostgreSQL 18 thay đổi nền tảng đó bằng hệ thống Asynchronous I/O (AIO), cho phép các tiến trình gửi nhiều yêu cầu I/O song song trước khi kết quả đầu tiên trở về, khai thác đúng thế mạnh của storage hiện đại.
Tại sao PostgreSQL 18 quan trọng với kiến trúc của bạn?
Nếu bạn đang vận hành hệ thống OLTP quy mô hàng chục đến hàng trăm nghìn giao dịch mỗi giây, PostgreSQL 18 mang lại bốn thay đổi nền tảng tác động trực tiếp đến thiết kế bảng, thiết kế index, thiết kế schema migration và thiết kế xác thực kết nối. Đây không phải là một phiên bản "nâng cấp tùy chọn" - đây là phiên bản bạn nên lên kế hoạch kiểm thử và chuyển đổi nghiêm túc trong chu kỳ hai quý tới.
2. Từ PostgreSQL 15 đến PostgreSQL 18 - Bản đồ tiến hóa
Để hiểu được sự khác biệt của PostgreSQL 18, cần nhìn lại bốn bản phát hành gần nhất - mỗi bản giải một bài toán khác nhau, và PostgreSQL 18 chính là mảnh ghép cuối để PostgreSQL đứng vững ở tầng dữ liệu lõi của các kiến trúc cloud-native hiện đại.
ICU collation mặc định cho cluster. Đây là bản đánh dấu sự trở lại của PostgreSQL với các tính năng SQL tiêu chuẩn.libpq, tối ưu bulk loading. Bản này tập trung vào scale-out và high availability.pg_basebackup --incremental, MAINTAIN privilege, JSON_TABLE, pg_createsubscriber. Bản này nâng cấp công cụ vận hành và backup.io_uring, B-tree Skip Scan, Virtual Generated Columns mặc định, UUIDv7, OAuth 2.0 authentication, RETURNING OLD/NEW, temporal constraints WITHOUT OVERLAPS, protocol 3.2.3. Asynchronous I/O - Lớp nền tảng được viết lại
Đây là tính năng lớn nhất và cũng là tính năng khó hình dung nhất của PostgreSQL 18. Để hiểu được giá trị của AIO, cần nhìn lại cách PostgreSQL xử lý một lần đọc heap block trước khi nâng cấp.
3.1. Mô hình cũ - Synchronous I/O với readahead thụ động
Với sequential scan trên một bảng lớn, PostgreSQL 17 trở về trước hoạt động đại khái như sau:
- Tiến trình backend gọi
ReadBuffer()để lấy block tiếp theo. - Nếu block không có trong
shared_buffers, hàmsmgrread()thực hiện system callpread(). - Kernel chặn tiến trình (state
D- uninterruptible sleep) cho đến khi disk trả về trang 8KB. - Tiến trình được đánh thức, xử lý trang đó, rồi lặp lại bước 1 cho block kế tiếp.
Nhìn bề ngoài thì OS đã có readahead (đọc trước) ở tầng block layer, giúp phần nào che giấu độ trễ. Nhưng readahead của OS là suy đoán: nó chỉ hoạt động tốt khi access pattern liên tục và kích thước block phù hợp. Đối với bitmap heap scan - vốn đọc các block phân tán theo vị trí trong index - OS readahead gần như vô dụng, và PostgreSQL phải chịu đầy đủ độ trễ của từng seek.
sequenceDiagram
participant B as Backend
participant K as Kernel
participant D as Disk
B->>K: pread block 1
K->>D: issue read
D-->>K: data block 1
K-->>B: return
Note over B: process block 1
B->>K: pread block 2
K->>D: issue read
D-->>K: data block 2
K-->>B: return
Hình 1: Mô hình Synchronous I/O truyền thống - mỗi lần đọc là một lần chờ tuần tự
3.2. Mô hình mới - AIO với io_uring, worker và direct I/O
PostgreSQL 18 giới thiệu một lớp abstraction mới gọi là AIO Handle. Thay vì gọi trực tiếp pread(), tiến trình backend đăng ký yêu cầu đọc với AIO subsystem, rồi tiếp tục xử lý các công việc khác như tính toán predicate, giải nén cột, hay gọi operator. Khi block đã sẵn sàng, subsystem đánh thức backend để hoàn tất.
Tham số mới quan trọng nhất là io_method, có thể nhận một trong ba giá trị:
| io_method | Cơ chế hoạt động | Khi nào nên dùng |
|---|---|---|
sync | Giữ nguyên mô hình đồng bộ cũ - chỉ dùng làm fallback | Môi trường cần hành vi y hệt PostgreSQL 17 để so sánh |
worker | Dùng một pool các I/O worker nền (mặc định 3 worker), backend đẩy yêu cầu vào queue và đợi kết quả qua shared memory | Linux kernel cũ, macOS, FreeBSD, mọi nền tảng không có io_uring |
io_uring | Dùng trực tiếp io_uring của Linux (kernel ≥ 5.1). Mỗi backend có một submission queue riêng, yêu cầu được đẩy xuống kernel qua ring buffer không copy | Linux hiện đại, NVMe, NVMe-over-Fabrics, cần throughput tối đa |
sequenceDiagram
participant B as Backend
participant A as AIO Subsystem
participant K as Kernel io_uring
participant D as NVMe
B->>A: submit read block 1..32
A->>K: io_uring_enter SQEs
par Parallel dispatch
K->>D: read block 1
and
K->>D: read block 2
and
K->>D: read block 32
end
Note over B: CPU works on predicates
D-->>K: completions
K-->>A: CQEs via ring
A-->>B: wake backend when needed
Hình 2: AIO với io_uring - backend gửi batch 32 yêu cầu đọc rồi tiếp tục làm việc CPU
3.3. Tác động thực tế lên các loại query
Điểm cần nhớ: AIO không phải "đũa thần" tăng tốc mọi query. Hiệu ứng phân biệt rõ theo loại access pattern:
- Sequential Scan và Bitmap Heap Scan: tăng tốc 2-3 lần, đặc biệt trên NVMe và storage có độ trễ cao nhưng băng thông lớn.
- VACUUM và ANALYZE: nhanh hơn đáng kể do cả hai đều đọc block theo phân đoạn rộng.
- Index Scan (nhất là B-tree random lookup): chưa được hưởng lợi nhiều trong phiên bản này - đây là công việc còn dang dở, dự kiến hoàn thiện ở PostgreSQL 19.
- Short OLTP query (PK lookup, update theo id): hầu như không thay đổi, vì các block đã nằm sẵn trong
shared_buffers.
Gợi ý cấu hình khởi đầu
Trên Linux 6.x với NVMe: bắt đầu với io_method = io_uring, effective_io_concurrency = 64 và maintenance_io_concurrency = 128. Theo dõi pg_stat_io (đã có từ PostgreSQL 16) trước và sau chuyển đổi để định lượng chính xác lợi ích thay vì đoán mò.
4. B-tree Skip Scan - Giải thoát khỏi giới hạn left-most prefix
Đây là tính năng mà các DBA dày dạn sẽ reo lên khi nghe tin. Trong suốt lịch sử PostgreSQL, một quy tắc bất thành văn đã tồn tại: "index multi-column chỉ dùng được khi truy vấn có điều kiện trên cột đầu tiên". Giới hạn này xuất phát từ cách B-tree sắp xếp entry theo thứ tự từ điển - nếu bạn không biết giá trị cột đầu, bạn không biết bắt đầu đọc ở đâu trong cây.
4.1. Vấn đề thực tế
Hãy tưởng tượng bạn có bảng orders với hơn 100 triệu dòng và một index composite:
CREATE INDEX idx_orders_status_customer_date
ON orders (status, customer_id, order_date);
Truy vấn sau đây trên PostgreSQL 17 sẽ không dùng được index và buộc phải chạy Sequential Scan:
SELECT * FROM orders
WHERE customer_id = 42
AND order_date >= '2026-01-01';
Để tránh, DBA buộc phải tạo thêm index (customer_id, order_date) - nhân đôi chi phí storage, chi phí write amplification và chi phí bảo trì VACUUM.
4.2. Cơ chế Skip Scan hoạt động
PostgreSQL 18 bổ sung một bước mới trong B-tree traversal: khi planner phát hiện index có cột đầu low cardinality (số giá trị phân biệt thấp, ví dụ status chỉ có 5 giá trị), nó tự động tạo ra một loạt "probe" - mỗi probe là một lần tìm kiếm riêng biệt với một giá trị cụ thể của cột đầu. Về mặt logic, planner biến truy vấn gốc thành:
SELECT * FROM orders
WHERE status IN ('new', 'paid', 'shipped', 'delivered', 'cancelled')
AND customer_id = 42
AND order_date >= '2026-01-01';
Nhưng danh sách giá trị được lấy động từ chính B-tree, không cần bảng meta và không cần lookup trực tiếp.
4.3. Con số benchmark cụ thể
Trên một bảng 1 triệu dòng với index ba cột, tài liệu kỹ thuật của pgEdge đo được:
| Phiên bản | Kế hoạch thực thi | Thời gian thực thi |
|---|---|---|
| PostgreSQL 17 | Sequential Scan | 48.527 ms |
| PostgreSQL 18 | Index Only Scan (skip scan) | 12.801 ms |
Tỉ lệ cải thiện khoảng 74%. Nhưng con số quan trọng hơn là giảm đáng kể số lượng index dư thừa cần tạo - trên các hệ thống cũ có hàng chục index chồng chéo vì từng phải "phá giới hạn left-most", lợi ích dài hạn về storage và tốc độ write có thể còn lớn hơn chính con số 74% kia.
Hai điều cần lưu ý
Thứ nhất, Skip Scan chỉ hoạt động hiệu quả khi cột đầu có cardinality thấp - nếu cột đầu là customer_id với hàng triệu giá trị, planner sẽ không chọn skip scan vì chi phí probe lớn hơn full scan. Thứ hai, điều kiện trên các cột sau phải là equality hoặc range hợp lý; nếu là hàm phức tạp như lower(email) LIKE '%abc%', B-tree vẫn bó tay.
5. Virtual Generated Columns - Mặc định mới
PostgreSQL 12 đã giới thiệu Generated Columns, nhưng chỉ hỗ trợ STORED - tức giá trị được tính tại thời điểm ghi và lưu vật lý trong heap. Cách này nhanh khi đọc, nhưng tốn dung lượng và làm UPDATE nặng hơn khi công thức sinh cột phức tạp. PostgreSQL 18 đảo ngược mặc định: từ nay, GENERATED ALWAYS AS ... sẽ được hiểu là VIRTUAL, tức tính tại thời điểm đọc, không chiếm dung lượng vật lý.
CREATE TABLE user_profile (
user_id BIGINT PRIMARY KEY,
settings JSONB NOT NULL,
username VARCHAR(100)
GENERATED ALWAYS AS (settings ->> 'username') VIRTUAL,
display_name VARCHAR(200)
GENERATED ALWAYS AS (
coalesce(settings ->> 'display_name', settings ->> 'username')
) VIRTUAL
);
Trong ví dụ này, hai cột username và display_name không chiếm một byte nào trên đĩa. Chúng chỉ được tính khi SELECT, dùng toán tử ->> bóc từ trường settings. Khi payload JSON thay đổi, bạn không cần chạy UPDATE trên cột sinh - chính là ưu điểm lớn nhất so với cách cũ.
5.1. Khi nào nên dùng VIRTUAL, khi nào nên dùng STORED
| Tiêu chí | VIRTUAL | STORED |
|---|---|---|
| Chi phí ghi | Rất thấp | Cao nếu công thức phức tạp |
| Chi phí đọc | Tăng nhẹ (tính lại mỗi lần) | Rất thấp |
| Dung lượng đĩa | 0 byte | Đầy đủ kích thước cột |
| Index trên cột sinh | Được phép (expression index) | Được phép |
| Logical replication | Không replicate giá trị | Replicate (mới trong PG18) |
| Trường hợp dùng điển hình | View-like projection từ JSONB | Cột tính toán nặng dùng thường xuyên |
Điểm đáng chú ý cho logical replication
PostgreSQL 18 bổ sung khả năng logical replication cho STORED generated columns. Trước đây, bạn phải tự tính lại cột sinh bên subscriber - nguyên nhân của vô số lỗi lệch dữ liệu. Từ PG18, giá trị được streaming nguyên vẹn, giảm đáng kể áp lực CPU ở subscriber trong các kiến trúc replica phân vùng theo tenant.
6. UUIDv7 - Kết thúc cuộc tranh cãi về primary key
UUID v4 từ lâu đã là lựa chọn mặc định cho primary key trong các hệ thống phân tán, nhờ tính ngẫu nhiên và không cần đồng bộ giữa các node. Nhưng chính tính ngẫu nhiên đó lại là vấn đề: khi hàng mới rải đều trên toàn bộ không gian 128-bit, B-tree phải thực hiện nhiều page split, write amplification cao, và cache locality gần như bằng không.
6.1. Cấu trúc bit của UUIDv7
UUIDv7 theo RFC 9562 có cấu trúc:
graph LR
A["48 bits timestamp Unix ms"] --> B["4 bits version 7"]
B --> C["12 bits rand_a sub-ms counter"]
C --> D["2 bits variant"]
D --> E["62 bits rand_b random"]
style A fill:#e94560,stroke:#fff,color:#fff
style B fill:#0f3460,stroke:#fff,color:#fff
style C fill:#4CAF50,stroke:#fff,color:#fff
style D fill:#0f3460,stroke:#fff,color:#fff
style E fill:#ff9800,stroke:#fff,color:#fff
Hình 3: Bố cục bit của UUIDv7 - 48 bit đầu là timestamp, đảm bảo thứ tự thời gian
Nhờ 48 bit timestamp ở đầu, UUIDv7 được sắp xếp gần đúng theo thời gian. Khi dùng làm primary key, các hàng mới được chèn vào cuối cây B-tree - giống hệt hành vi của bigserial - loại bỏ hoàn toàn hiện tượng page split rải rác.
6.2. Hàm mới trong PostgreSQL 18
-- Sinh UUIDv7 hiện tại
SELECT uuidv7();
-- Sinh UUIDv7 với offset (hữu ích cho test dữ liệu quá khứ)
SELECT uuidv7(interval '-1 day');
-- Trích timestamp từ UUIDv7
SELECT uuid_extract_timestamp('018f5a1e-3c80-7000-8000-0123456789ab'::uuid);
-- Alias mới cho gen_random_uuid
SELECT uuidv4();
Điểm tinh tế là 12 bit rand_a được PostgreSQL dùng làm bộ đếm phụ trong khoảng sub-millisecond, đảm bảo hai UUIDv7 sinh trong cùng một backend và cùng một millisecond vẫn có thứ tự tăng dần. Tính monotonicity này chỉ đúng trong phạm vi một backend - giữa nhiều connection song song, thứ tự chỉ gần đúng theo millisecond.
Chiến lược migration primary key
Bạn không cần chuyển đổi các bảng đang dùng UUIDv4. Chỉ cần thay DEFAULT gen_random_uuid() bằng DEFAULT uuidv7() cho các bảng mới hoặc cột mới, và theo dõi chỉ số cache hit ratio trong vài tuần. Trên hệ thống với tỉ lệ insert cao, bạn sẽ thấy shared_buffers hit rate tăng rõ rệt do cache locality tốt hơn.
7. OAuth 2.0 Authentication - Chia tay cơ chế password đơn thuần
PostgreSQL 18 bổ sung phương thức xác thực oauth trong pg_hba.conf, cho phép kết nối dùng bearer token từ Identity Provider (Keycloak, Okta, Azure AD, Authentik, Google Identity...) thay vì password. Đây là lần đầu tiên PostgreSQL tích hợp OAuth ở cấp giao thức, chứ không phải qua extension bên ngoài.
sequenceDiagram
participant App as Application
participant IdP as Identity Provider
participant PG as PostgreSQL 18
App->>IdP: request token scope db.read
IdP-->>App: access_token JWT
App->>PG: connect oauth_token=...
PG->>IdP: validate token
IdP-->>PG: active true sub user
PG-->>App: session established
Note over PG,App: subsequent SQL with role mapped from sub
Hình 4: Luồng xác thực OAuth 2.0 Client Credentials giữa ứng dụng và PostgreSQL 18
7.1. Cấu hình trong pg_hba.conf
host all all 0.0.0.0/0 oauth issuer="https://idp.example.com/realms/anhtu" \
scope="openid db.connect" \
map=oauth_role_map
File pg_ident.conf dùng để ánh xạ từ trường sub hoặc email trong JWT sang role PostgreSQL, cho phép quản lý quyền ở tầng database mà không cần tạo password riêng cho từng người dùng.
7.2. Hai luồng xác thực phổ biến
Luồng Device Authorization dùng cho psql tương tác - người dùng chạy psql, PostgreSQL trả về mã xác thực, người dùng mở trình duyệt và xác thực:
psql "host=db.anhtu.dev oauth_issuer=https://idp.example.com \
oauth_client_id=psql-cli dbname=app"
# Visit https://idp.example.com/device and enter code FPQ2-M4BG
Luồng Bearer Token dùng cho ứng dụng đã tự lấy token từ IdP (ví dụ service dùng client credentials grant):
psql "host=db.anhtu.dev oauth_issuer=https://idp.example.com \
oauth_client_id=backend-svc oauth_token=eyJhbGciOi... dbname=app"
md5 password đang trên đường bị loại bỏ
PostgreSQL 18 chính thức deprecate md5 password authentication. Cộng đồng khuyến nghị chuyển sang SCRAM-SHA-256 ngay lập tức. Nếu bạn vẫn dùng md5 vì lý do tương thích client cũ, hãy lên kế hoạch rollover trước khi bản phát hành tiếp theo loại bỏ hoàn toàn.
8. RETURNING OLD/NEW - Audit trail viết lại gọn hơn
Mệnh đề RETURNING vốn rất tiện cho việc lấy giá trị sau INSERT hoặc UPDATE. PostgreSQL 18 mở rộng nó để có thể lấy đồng thời giá trị cũ và mới trong cùng một câu lệnh, áp dụng cho INSERT, UPDATE, DELETE và MERGE:
UPDATE orders
SET status = 'paid',
paid_at = now()
WHERE id = 1024
RETURNING OLD.status AS old_status,
NEW.status AS new_status,
OLD.paid_at AS old_paid_at,
NEW.paid_at AS new_paid_at;
Trước đây, để có đủ hai phiên bản dữ liệu phục vụ audit trail, bạn phải viết CTE hai bước hoặc dùng trigger BEFORE UPDATE lưu snapshot. PostgreSQL 18 cho phép làm điều đó trong một statement, giảm một round trip và gọn hơn hẳn trong ORM như Entity Framework Core, Npgsql hay sqlx.
9. Temporal Constraints - WITHOUT OVERLAPS và PERIOD
Đây là một trong những tính năng ít người chú ý nhưng cực kỳ hữu ích cho các hệ thống đặt phòng, booking, lịch làm việc, tenant billing - bất cứ nơi nào cần ràng buộc "không được chồng khoảng thời gian". PostgreSQL 18 bổ sung:
CREATE TABLE room_booking (
id BIGSERIAL,
room_id BIGINT NOT NULL,
period TSTZRANGE NOT NULL,
PRIMARY KEY (room_id, period WITHOUT OVERLAPS)
);
Với khai báo trên, PostgreSQL sẽ tự động từ chối bất kỳ dòng nào có cùng room_id và khoảng period giao cắt với một bản ghi đã tồn tại. Trước PG18, bạn buộc phải dùng EXCLUDE USING gist - đúng, nhưng cú pháp dài và khó giải thích cho developer mới vào nghề.
Tương tự, foreign key có thể khai báo PERIOD period để đảm bảo khoảng thời gian của hàng con nằm gọn trong khoảng của hàng cha - lần đầu tiên PostgreSQL hỗ trợ ngữ nghĩa temporal referential integrity ở mức DDL.
10. pg_upgrade và bảo toàn thống kê planner
Một trong những nỗi đau kinh điển của các DBA là: sau pg_upgrade, thống kê planner bị xóa sạch, phải chạy ANALYZE toàn bộ cluster, và trong khoảng thời gian đó hệ thống chạy chậm thảm hại do planner dùng kế hoạch tồi. PostgreSQL 18 giải bài toán này theo hai hướng:
- Bảo toàn thống kê optimizer:
pg_upgradechuyển thống kê trongpg_statisticsang cluster mới thay vì bỏ qua. Hệ thống sẵn sàng phục vụ traffic production ngay sau khi upgrade hoàn tất. - Cờ
--swapmới: thay vì copy toàn bộ thư mục dữ liệu hoặc dùng hard link, pg_upgrade có thể hoán đổi trực tiếp data directory. Đặc biệt hữu ích với cluster hàng TB. - Cờ
--jobsnâng cấp: song song hóa phần vận hành dump/restore ở mức schema, rút ngắn downtime đáng kể với cluster có hàng chục nghìn bảng.
Chiến lược chuyển đổi thực tế
Với cluster nhỏ dưới 500GB, bạn có thể upgrade in-place trong cửa sổ bảo trì ngắn. Với cluster lớn hơn, khuyến nghị dùng logical replication để chuẩn bị replica PG18 song song, sau đó switchover - thay vì chịu downtime. PostgreSQL 17 đã hỗ trợ logical replication từ standby, nên thao tác này ít rủi ro hơn nhiều so với vài năm trước.
11. Logical Replication - Những cải tiến lặng lẽ nhưng quan trọng
PostgreSQL 18 tiếp tục hoàn thiện logical replication, tập trung vào ba vấn đề thường gặp trong production:
- Idle replication slot timeout: tham số mới
idle_replication_slot_timeoutcho phép tự động xóa các slot không hoạt động trong khoảng thời gian cho trước. Kết thúc thời kỳ "WAL tràn ổ đĩa vì một slot bị quên" - nguyên nhân hàng đầu của sự cố production PostgreSQL suốt 5 năm qua. - Parallel streaming mặc định:
CREATE SUBSCRIPTIONmặc định bật streaming song song cho các transaction lớn, không cần tinh chỉnh thủ công. - Báo cáo write conflict: khi subscriber gặp xung đột ghi (ví dụ duplicate key), chi tiết được ghi vào log và view
pg_stat_subscription_stats, thay vì chỉ báo lỗi chung chung như trước. pg_createsubscriber --all: tạo logical replica cho tất cả database trong cluster bằng một lệnh duy nhất.
12. Wire Protocol 3.2 - Cập nhật đầu tiên sau 22 năm
Đây là sự kiện ngầm rất đáng chú ý: wire protocol version 3.2 là bản nâng cấp đầu tiên kể từ version 3.0 phát hành cùng PostgreSQL 7.4 năm 2003. Thay đổi lớn nhất là mở rộng cancellation secret từ 4 byte cố định lên độ dài biến đổi, tăng cường bảo mật chống tấn công brute force hủy query. Ngoài ra protocol 3.2 còn đặt nền cho các tính năng giao tiếp streaming hiệu năng cao trong tương lai.
Để giữ tương thích, libpq mặc định vẫn dùng 3.0 - client chủ động opt-in qua tham số min_protocol_version=3.2 khi cần. Các driver cấp cao hơn (Npgsql, JDBC, asyncpg, pgx) sẽ bổ sung hỗ trợ dần dần trong các bản minor sắp tới.
13. Observability - EXPLAIN và pg_stat_io nâng cấp
PostgreSQL 18 làm cho việc "đọc kế hoạch thực thi" trở nên dễ hiểu hơn đáng kể:
EXPLAIN ANALYZEgiờ tự động hiển thị buffer access counts, không cần thêmBUFFERS. Bạn lập tức thấy ngay một plan đang "đốt" bao nhiêu shared hit, bao nhiêu read từ đĩa.- Trong
EXPLAIN ANALYZE VERBOSE, có thêm thống kê CPU time, WAL generated, average read time cho mỗi node - cực kỳ hữu ích để tách biệt vấn đề do CPU hay do I/O. pg_stat_all_tablesbổ sung thời gian của các thao tác vacuum (heap scan, index vacuum, heap truncate...), giúp phân tích nguyên nhân "vacuum bị chậm".pg_stat_activityvàpg_stat_iobổ sung thống kê per-connection về I/O và WAL, thay vì chỉ có ở mức global.
14. Unicode, casefold và tìm kiếm không phân biệt hoa thường
Với ứng dụng đa ngôn ngữ, PostgreSQL 18 mang đến hai cải tiến đáng giá:
-- Collation mới, ngữ nghĩa Unicode đầy đủ với tốc độ cao
CREATE COLLATION unicode_fast (
provider = builtin,
locale = 'PG_UNICODE_FAST',
deterministic = false
);
-- Hàm casefold - thay thế lower() cho so sánh không phân biệt hoa thường
SELECT casefold('TU Anh') = casefold('tu anh'); -- true
casefold() đặc biệt hữu ích khi so sánh tên tiếng Đức (có ß), tiếng Thổ Nhĩ Kỳ (có dotless i), hay bất cứ ngôn ngữ nào có ngữ nghĩa case khác tiếng Anh - những trường hợp mà lower() cho kết quả sai. LIKE giờ cũng hỗ trợ pattern matching với nondeterministic collation, điều mà trước đây phải né tránh bằng regex phức tạp.
15. Checklist chuyển đổi PostgreSQL 17 → 18
Dưới đây là danh sách các bước thực tế mà một đội ngũ vận hành có thể áp dụng để chuyển đổi an toàn:
- Audit các extension đang dùng. Kiểm tra
pgvector,TimescaleDB,PostGIS,citus,pg_cron... đã có bản hỗ trợ PG18 chưa. Đây thường là vật cản chính. - Kiểm tra pgbouncer và connection pooler. Nâng lên phiên bản tương thích protocol 3.2, kể cả khi bạn chưa opt-in, để tránh regression trong tương lai.
- Chuyển md5 sang SCRAM. Rà soát
pg_hba.conf, đổi các dòngmd5thànhscram-sha-256, và chạyALTER USER ... WITH PASSWORDđể tái sinh password hash dưới dạng mới. - Thử nghiệm AIO trong staging. Bắt đầu với
io_method = worker, đo benchmark vớipgbenchvà workload thực tế, rồi chuyển sangio_uringnếu kernel ≥ 5.1. - Rà soát generated column. Các cột
GENERATED STOREDtrong schema cũ không đổi tự động. Nhưng các cột mới cần khai báo rõSTOREDnếu không muốn nhận mặc định mới là VIRTUAL. - Thí điểm Skip Scan. Tìm các bảng lớn có index multi-column không dùng được vì left-most prefix, chạy lại
EXPLAIN ANALYZEtrên PG18 để xác minh planner đã chọn skip scan. - Kiểm tra backup/restore pipeline. Xác nhận công cụ backup của bạn (pgBackRest, Barman, wal-g) đã nhận diện
pg_upgrade --swapvà các thay đổi về WAL format. - Cập nhật monitoring. Thêm metric từ
pg_stat_iomới, dashboard theo dõiidle_replication_slot_timeout, và cảnh báo trên các trường mới trongpg_stat_subscription_stats.
16. Lời kết
Nếu nhìn dưới lăng kính "feature list" đơn thuần, PostgreSQL 18 có vẻ là một bản cập nhật dày dặn nhưng không cách mạng. Nhưng nếu nhìn dưới lăng kính kiến trúc, đây là phiên bản đặt lại nền móng: lớp I/O được viết lại, planner học một trick mới mà giới DBA mong đợi từ hai thập kỷ, wire protocol cập nhật lần đầu sau 22 năm, và cơ chế xác thực bước vào kỷ nguyên token-based thay vì password.
Với các hệ thống đang chạy PostgreSQL 15 hoặc 16, đây là thời điểm hợp lý để lên kế hoạch chuyển đổi trong 6-9 tháng tới. Với những hệ thống mới bắt đầu, không có lý do gì để không chọn thẳng PostgreSQL 18 ngay từ đầu - đặc biệt khi các nhà cung cấp cloud lớn như AWS RDS, GCP Cloud SQL, Azure Database for PostgreSQL, Aiven, Neon, Supabase đều đã hoặc đang hoàn tất việc đưa PG18 lên sản phẩm.
Điều cần nhớ: hiệu năng của PostgreSQL 18 không tự đến. AIO cần cấu hình đúng, Skip Scan cần đúng hình dạng index, UUIDv7 cần được dùng cho các bảng mới, OAuth cần IdP hoạt động ổn định. Đây là một công cụ mạnh, nhưng giá trị của nó phụ thuộc vào mức độ hiểu biết của đội ngũ vận hành - và đó chính là lý do bài viết này tồn tại: để bạn có được bức tranh đầy đủ trước khi bắt tay vào thực hiện chuyển đổi.
17. Nguồn tham khảo
- PostgreSQL 18 Released - Official announcement (25/09/2025)
- PostgreSQL 18 Release Notes - Tài liệu chính thức
- Crunchy Data - Get Excited About Postgres 18
- Xata - Going Down the Rabbit Hole of Postgres 18 Features
- pgEdge - Postgres 18 Skip Scan Deep Dive
- Neon - PostgreSQL 18 New Features
- Aiven - Welcome PostgreSQL 18
- RFC 9562 - UUID Formats (UUIDv7 specification)
Vue 3.6 Vapor Mode 2026 - Compile-time Reactivity bỏ Virtual DOM, Pinia 3, Nuxt 4 Hybrid Rendering, TanStack Query, Vite 6 Rolldown và Kiến trúc Frontend Production cho Backend .NET 10
eBPF 2026 - Kiến trúc Observability, Networking và Runtime Security cho Linux Production với Cilium, Tetragon, Parca, OpenTelemetry eBPF, XDP, Sockmap, CO-RE và Auto-instrumentation không Sidecar
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.