PostgreSQL 18

Toàn bộ tính năng mới của postgresql 18 có trong link này https://www.postgresql.org/docs/18/release-18.html. Ở bài viết này, mình chỉ lấy những tính năng mà mình thấy khá ok đối với mình.

Asynchronous i/o

Đây là một cải tiến mới trong cách đọc dữ liệu từ đĩa cứng, thay vì đợi disk đọc xong rồi trả về, thì pg sẽ giao nhiệm vụ đọc cho các worker, trong quá trình worker chạy đi đọc dữ liệu, pg sẽ xử lý công việc khác, không có đứng đợi. Cơ chế này kết hợp với io_uring của linux 5.1+ , giúp tốc độ đọc như bay.

Default sẽ có 3 thằng worker chịu trách nhiệm đọc dữ liệu. Nếu bạn host pg trên con máy chủ khỏe, ví dụ 512 nhân, 1024 luồng, bạn có thể tăng số lượng worker lên (256 , chẳng hạn)

Các worker có cơ chế gom cục các lệnh đọc ( batch reads), giúp tiết kiệm thời gian.

Để đảm bảo tính ACID, thì lệnh write vẫn là synchronous

Việc chia worker cho read ảnh hưởng mạnh tới các tác vụ sau

  • Quét toàn bộ bảng

  • Duyệt dữ liệu qua index (bitmap heap scan)

  • Database VACUUM ( nhiều ae làm data chắc cũng gặp khốn khổ với thằng ông nội này)

Để theo dõi các worker làm việc có hiệu quả không, đang làm cái gì, pg sinh ra thằng pg_aios. Đây là là một bảng thông tin chi tiết, giúp người quảng trị viên monitor thằng pg và điều chỉnh số lượng worker cho hợp lý mà không cần đoán mò. Ví dụ thấy trong hàng đợi toàn 100s, nghĩa là có vẻ như cần tăng worker lên.

ngoài ra, một vũ khí tối thường được hỗ trợ là posix_fadvise, posix_fadvise có nhiệm vụ báo trước, xi nhanh trước cho os là sắp đọc toàn bộ bảng, hãy load nó lên trên ram và để giành trước đi. Vũ khí này cực kỳ lợi hại khi chúng ta đọc tuần tự, pg sẽ tự nhắn os trước là sắp đọc đến batch tiếp theo, chuẩn bị trước đi.

Rõ ràng các vũ khí này là sân chơi cho các tay to, nơi thừa cpu, thừa ram, thậm chí ổ cứng hỗ trợ tốc độ đọc cao gấp rất nhiều lần so với các ổ cứng cá nhân chúng ta sở hữu. Người quản trị viên không thiếu phần cứng, chỉ thiếu vũ khí giúp tận dụng tối ta phần cứng.

Còn, với cá nhân học tập yêu khoa học, hoặc mấy máy chủ be bé, chắc bỏ qua đi hen.

UUIDv7

Rất nhiều dev sử dụng UUIDv4 làm khóa chính, UUIDv4 đảm bảo khóa gần như duy nhất , ngẫu nhiên. Điểm yếu cố hữu của UUIDv4 là không có tính tuần tự, làm cho phân mảnh chỉ mục. Kết quả là việc update hoặc insert chậm hơn so với các khóa tự tăng khác như serial int, Snowflake ID, tốn thời gian reindex lại.

UUIDv7 ra đời, ịn thêm 60 bit đầu tiên, là thời gian tính bằng mini giây kể từ năm 1970, 6 bit meta, phần còn lại ngẫu nhiên hoặc sequence . Vừa unique, vừa nhanh, vừa bảo mật, đã giải quyết các vấn đề của UUIDv4

Cá nhân mình thì thích Snowflake ID hơn, chỉ tốn 64 bit (8B), so với uuidv7 128 bit (16B), giúp nhẹ database hơn (he he)

B-tree skip scans

Đặt tình huống như thế này , thường tháy

Ta có bảng đơng hàng, có nhiều cột, mà có 2 cột được index là ngày và trạng thái, công ty bán hàng hơn 10 năm, nghĩa là có > 3650 giá trị ngày khác nhau. Còn trạng thái đơn hàng thì chỉ có lèo tèo vài cái là lên đơn, đã thanh toán, kết thúc thành công, hủy đơn …

Với các phiên bản postgresql <18 , nếu ta truy vấn dữ liệu theo ngày mà không có status, có khi sẽ table scan, hoặc index scan để tìm ra đơn hàng ngày mà chúng ta truy vấn.

Với pg 18, pg sẽ liệt kê các status của chúng ta, sau đó nhảy vào từng status, nhảy vào cái dữ liệu date của status đó. Ví dụ chúng ta có 4 trạng thái status là lên đơn, đã thanh toán, kết thúc thành công, hủy đơn, và kiếm dữ liệu ngày 2025-09-14, pg sẽ nhảy cóc vào status lên đơn, nhảy vào ngày 2025-09-14, sau đó sẽ nhảy vào status đã thanh toán, nhảy vào ngày 2025-09-14, làm tương tự cho kết thúc thành công, hủy đơn.

Điều kiện cho B-tree skip scans xảy ra là

  • Chúng ta có 1 cột nhiều, 1 cột siêu ít, trong index ( nếu cái status có tầm 100 status thì cái B-tree skip scans không xảy ra đâu, nhảy cóc gì lắm thế)

  • Dùng toán tử = ở cột nhiều ( ở đây là chúng ta kiếm đơn hàng trong ngày 2025-09-14, chứ nếu kiếm >= 2025-09-14 hoặc <2025-09-14 , gì đó, thì thua)

  • Cái nữa là pg sẽ tự làm cái này cho chúng ta, tự phân chia sau khi chúng ta tạo index, tự tái cấu trúc index lại dựa trên dữ liệu.

Thật tuyệt vời phải không các bạn.

Virtual generated columns

Từ phiên bản pg 12, pg có hỗ trợ generated columns

1colname datatype GENERATED ALWAYS AS (expression) STORED

Nhưng ở dạng STORED, không có ở dạng Virtual như mysql. Ngoài ra, expression phải là immutable expression. Vấn đề là chúng ta phải tốn disk để lưu cột column name này. Và không đảm bảo value của colname thay đổi khi giá trị của expression thay đổi.

Với pg18, có hỗ trợ onfly column. Nghĩa là chúng ta sẽ được cột ảo thực sự, truy xuất dữ liệu vào source, không tốn disk lưu dữ liệu. Thật tuyệt với phải không nào.

Tưởng tưởng, chúng ta có bảng user, có trường json info -> username , giờ chỉ cần lôi cái username ra ngoài, truy vấn vẫn là user.username , okela.

OAuth 2.0

PG bản 18 hỗ trợ OAuth 2.0, okta, Keycloak, giờ cấp quyền cho ông dev cực dễ. Dev vào công ty, đăng nhập, Keycloak cấp key quyền, có quyền access db, cứ cầm key quyền đi vào db. Hè Hè, khỏi phải tình trạng user pg dev được share cho chục ông dev, rồi sự cố không biết ông nào làm. Mà tạo cho 1 ngàn tài khoảng dev thì quản lý mệt.

Còn nhiều cái mới, hay ho, xịn sò , bà con đọc ở https://www.postgresql.org/docs/18/release-18.html đi

Hy vọng cách chia mục rõ ràng này sẽ giúp bạn dễ dàng nắm bắt nội dung và sử dụng cho bài viết của mình!

Comments