Lập trình 22/09/2026 6 phút

Deadlock trong PostgreSQL: khóa chéo, 'deadlock detected', và cách tránh bằng thứ tự khóa

Hai giao dịch khóa chéo nhau — A giữ hàng 1 xin hàng 2, B giữ hàng 2 xin hàng 1 — là công thức của deadlock. Bài này tạo deadlock thật trên pg-lab: PostgreSQL tự phát hiện vòng chờ và hủy một nạn nhân với ERROR deadlock detected, giao dịch kia đi tiếp. Và cách tránh triệt để: luôn khóa các hàng theo cùng một thứ tự.

Lập trình 22/09/2026 6 phút

Bloat trong PostgreSQL: vì sao cập nhật một hàng 100.000 lần làm bảng phình lên 3,5 MB

MVCC khiến mỗi UPDATE để lại một bản chết thay vì sửa tại chỗ — và chúng tích tụ thành bloat. Bài này đo thật trên pg-lab: một bảng chỉ có 1 hàng sống, sau 100.000 lần UPDATE phình từ 8 KB lên 3,5 MB. VACUUM dọn bản chết nhưng không trả đĩa; chỉ VACUUM FULL mới thu nhỏ file về 8 KB — nhưng khóa bảng độc quyền.

Lập trình 22/09/2026 6 phút

VACUUM và autovacuum: cơ chế dọn bản chết tự động giữ PostgreSQL sống sót

Bloat (bài trước) sẽ bóp nghẹt database nếu không được dọn — và VACUUM là công cụ dọn đó. Bài này đo thật trên pg-lab: autovacuum TỰ chạy khi dead tuple vượt ngưỡng, đưa n_dead_tup từ 10.000 về 0 mà không cần một lệnh nào. Xem VACUUM VERBOSE báo cáo dọn 5000 tuple, không gian được tái dùng giữ kích thước ổn định, và vì sao đừng bao giờ tắt autovacuum.

Lập trình 22/09/2026 6 phút

HOT update và index-only scan: hai tối ưu MVCC mà fillfactor và index che phủ mở khóa

UPDATE trong PostgreSQL thường phải ghi lại mọi index — trừ khi là HOT update. Bài này đo thật trên pg-lab: với fillfactor mặc định 100, cập nhật cột không-index vẫn cho 0 HOT (trang đầy); hạ xuống 70 thì 4.368/10.000 là HOT (không ghi index). Và index-only scan cho Heap Fetches=0 khi query chỉ cần cột trong index, giảm I/O rõ rệt.

Lập trình 22/09/2026 6 phút

WAL trong PostgreSQL: vì sao ghi log trước khi ghi dữ liệu, và đo lượng WAL mỗi thao tác sinh ra

Độ bền của PostgreSQL đến từ WAL (write-ahead log): mọi thay đổi ghi vào log tuần tự và fsync xuống đĩa trước, trang dữ liệu ghi sau. Bài này đo thật trên pg-lab lượng WAL sinh ra: INSERT 10.000 hàng tạo 861 kB, COPY cùng dữ liệu chỉ 357 kB, UPDATE nặng nhất 1.645 kB, còn SELECT không sinh WAL. Kèm đánh đổi fsync và synchronous_commit.

Lập trình 22/09/2026 6 phút

SKIP LOCKED: xây hàng đợi công việc ngay trong PostgreSQL, 4 worker không đụng nhau

Bạn không phải lúc nào cũng cần RabbitMQ hay SQS cho hàng đợi công việc — PostgreSQL làm được bằng SELECT FOR UPDATE SKIP LOCKED. Bài này đo thật trên pg-lab: 4 worker chạy song song vét sạch 300 job, chia đều 76/75/75/74, mỗi job xử lý đúng một lần, không trùng, không chờ khóa. Kèm advisory lock cho khóa mức ứng dụng.