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

SELECT 1 chỉ 0,028ms, sao app chỉ chạy 1499 truy vấn/giây? Chi phí ẩn của mỗi kết nối

Đo truy vấn nhẹ ra 0,028ms rồi nhẩm 'app gọi vài chục nghìn lần một giây thoải mái'. Nhưng đó là khi tái dùng kết nối — mở kết nối mới mỗi lần chỉ còn 1499 tps, chậm 23 lần. Mỗi kết nối PostgreSQL là một tiến trình phải fork; chi phí mở đường lấn át chính truy vấn. Vì sao pool kết nối là lời giải, không phải tăng max_connections.

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

Hàng đang bị khóa mà vẫn đọc được ngay — vì sao khóa của CSDL chỉ chặn người ghi

A giữ SELECT FOR UPDATE trên một hàng: B ghi cùng hàng chờ 2 giây, nhưng ghi hàng khác hay đọc thuần không chờ mảy may. Tôi tưởng khóa chặn tất cả — hóa ra nó chỉ chặn người ghi cùng hàng, đọc luôn qua nhờ MVCC. Và khóa hai hàng ngược thứ tự thì deadlock, PostgreSQL tự hủy một bên.

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

Planner đoán 99 hàng, thực tế 10000 — bí mật nằm ở khoảng cách giữa 'rows' và 'actual rows'

Trên hai cột trùng nhau, planner đoán 99 hàng còn thực tế 10000 — lệch 100 lần. 'rows' của EXPLAIN là ước lượng (không chạy), 'actual rows' của EXPLAIN ANALYZE mới là đo thật (có chạy). Chính khoảng cách giữa hai con số tố cáo planner đang đoán mù — và EXPLAIN ANALYZE chạy thật cả UPDATE/DELETE.

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

Đánh index lên cột boolean rồi đợi truy vấn nhanh — nhưng PostgreSQL phớt lờ nó, và nó đúng

Truy vấn chọn lọc (1% hàng) dùng index nhanh 4,7 lần; nhưng trên cột boolean 50% hàng, planner bỏ index chọn seq scan. Tôi tưởng 'có index thì phải dùng index'. Index chỉ giúp khi truy vấn trả về ít hàng — và một index chết còn âm thầm làm chậm mọi lần ghi.

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

Bảng 81MB nhỏ hơn cache 128MB mà chạy 3 lần vẫn không nóng lên — bí mật của ring buffer

Lần đọc đầu là shared read (nạp trang), lần sau thành shared hit (từ RAM). Nhưng một seq scan bảng lớn KHÔNG vào cache dù bảng nhỏ hơn shared_buffers — vì ring buffer cố ý bảo vệ cache khỏi bị một lần quét lớn xóa sạch. Tôi tưởng 'chạy lại luôn nhanh hơn', hóa ra đó không phải luật tự nhiên.