Cơ sở dữ liệu 03/09/2026 9 phút

Prepared statement tưởng luôn nhanh — hóa ra có lúc quét cả bảng, chậm gấp trăm lần

Tưởng prepared statement luôn nhanh hơn nhiều — đo query nhẹ chỉ nhanh 13%. Nguy hơn: sau 5 lần chạy PostgreSQL có thể đổi sang generic plan, và trên cột lệch nó quét cả bảng 13ms thay vì index scan 0,13ms — nhanh ở khâu parse nhưng chậm gấp trăm ở khâu thực thi. Vẫn phải luôn tham số hóa, vì lý do quan trọng hơn tốc độ.

Cơ sở dữ liệu 03/09/2026 9 phút

Một BEGIN quên commit làm bảng phình gấp 3 — và VACUUM chạy trơn tru mà bất lực

Chạy VACUUM tưởng đã dọn sạch hàng chết, nhưng một phiên khác đang mở giao dịch dài giữ snapshot cũ, khiến VACUUM chạy không báo lỗi mà bảng vẫn chồng thêm 200k hàng chết mỗi vòng, phình lên gấp 3. Thủ phạm là một BEGIN bị quên commit. Đo bằng hai kịch bản y hệt, chỉ khác một giao dịch treo song song.

Cơ sở dữ liệu 03/09/2026 9 phút

Bảng đứng yên 14 MB, nhưng index âm thầm phình gấp đôi — và VACUUM không bao giờ cứu

VACUUM bảng sau mỗi vòng, thấy bảng đứng yên 14 MB nên tưởng mọi thứ gọn sạch. Nhưng index kẹt ở 8792 kB, mật độ lá chỉ 45% — phình gấp đôi, và VACUUM không bao giờ sửa nổi. Chỉ REINDEX mới nén lại cây. Vì sao phải đo cả index chứ không chỉ bảng, và HOT update giảm phình ngay từ đầu.

Cơ sở dữ liệu 03/09/2026 9 phút

Cột text 5KB tưởng làm chậm cả bảng — hóa ra vô hình, trừ khi bạn SELECT *

Tôi tưởng một cột text 5KB làm mọi truy vấn trên bảng chậm. Đo: SUM(tag) chỉ 1,5ms vì giá trị lớn nằm ngoài bảng chính, ở TOAST; chỉ khi truy vấn chạm cột đó mới chậm (420ms, ~280 lần). Và nén quyết định tất cả: cùng 5KB×50k hàng, text lặp còn 6,8 MB, dữ liệu ngẫu nhiên phình thành 300 MB.

Cơ sở dữ liệu 03/09/2026 9 phút

Index nhỏ hơn 128 lần nhờ chỉ đánh 1% dữ liệu — và vì sao WHERE status=$1 vẫn seq scan

Trên cột lệch 99% 'done', index đầy đủ 30 MB đánh cả những hàng chẳng ai tra; partial index chỉ 'active' còn 240 kB — nhỏ hơn 128 lần, ghi rẻ hơn 2 lần. Nhưng tạo xong rồi WHERE status=$1 vẫn seq scan cả bảng, vì planner không chứng minh được tham số khớp điều kiện index. Cách để index thật sự được dùng.

Cơ sở dữ liệu 03/09/2026 9 phút

Có index trên email mà WHERE lower(email) vẫn quét cả triệu hàng — và cú chữa hụt

Có index trên cột email nhưng WHERE lower(email)='...' vẫn quét cả bảng 7352 trang — một hàm bọc cột làm index cột trần vô dụng. Tạo index thẳng trên lower(email) thì cùng truy vấn còn 4 trang, nhanh gần 1800 lần. Nhưng đổi sang upper(email) là seq scan lại ngay, vì planner khớp biểu thức theo cú pháp chứ không theo ý nghĩa.