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

CTE và recursive CTE: viết query dễ đọc, duyệt cây — và bẫy MATERIALIZED chậm 1000 lần

CTE (WITH) chia query rối rắm thành các bước có tên, dễ đọc; recursive CTE duyệt cây/đồ thị chỉ bằng một câu SQL. Nhưng có một bẫy hiệu năng: bài này đo thật trong PostgreSQL — cùng một query lấy WHERE id=500000 trên bảng 1 triệu dòng, CTE thường (inline) dùng Index Scan chỉ 0.098ms, còn thêm MATERIALIZED buộc quét cả 1 triệu dòng mất 99.756ms — chậm hơn 1000 lần. Kèm recursive CTE dựng cây tổ chức từ CEO xuống.

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

Phân trang: vì sao OFFSET 1 triệu chậm 3000 lần, và keyset pagination giữ tốc độ phẳng

OFFSET LIMIT là cách phân trang ai cũng viết, và nó hoạt động hoàn hảo... cho tới trang thứ 50.000. Bài này đo thật trên bảng 2 triệu dòng: OFFSET chậm dần tuyến tính — trang đầu 0.029ms nhưng trang cuối 144.941ms, vì nó phải đọc qua 1.000.020 dòng chỉ để lấy 20. Keyset pagination (WHERE id > last_id) giữ ~0.04ms phẳng ở mọi trang. Kèm plan chứng minh OFFSET quét rồi vứt, keyset nhảy thẳng.

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

Statistics và planner: vì sao query 'đột nhiên chậm' — khi database đoán sai số dòng

Planner PostgreSQL không biết dữ liệu của bạn — nó ƯỚC LƯỢNG từ thống kê rồi chọn plan. Thống kê sai thì chọn plan tệ. Bài này đo thật: một bảng chèn 500.000 dòng nhưng chưa ANALYZE khiến planner ước lượng 1 dòng trong khi thực tế 5000 (chọn plan chậm 15.5ms); ANALYZE đưa về đúng, plan nhanh gấp đôi. Và cột tương quan (city suy ra country) khiến planner ước lượng thấp 4 lần — CREATE STATISTICS sửa từ ~23.000 về 99.500 sát thực tế 100.000.

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

Tối ưu query từ đầu tới cuối: cây quyết định, checklist, và một query từ 51ms xuống 3.7ms

Loạt SQL sâu đi qua 11 công cụ; bài cuối ghép chúng thành một quy trình. Query chậm không phải chuyện thử-sai — có cây quyết định rõ ràng bắt đầu từ EXPLAIN ANALYZE. Bài này đo thật một query chậm (JOIN + filter + ORDER BY LIMIT trên 2 triệu dòng): viết sargable một mình không đủ (vẫn 51ms), nhưng sargable + index đúng + ANALYZE đưa xuống 3.66ms — nhanh 14 lần. Kèm cây quyết định và checklist tối ưu.

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

MVCC trong PostgreSQL: vì sao đọc không chặn ghi, và UPDATE không sửa tại chỗ

Nhiều database khóa hàng khi đọc để tránh đọc dở dang — PostgreSQL thì không, nhờ MVCC. Bài này đo thật với hai phiên psql đồng thời: khi phiên A UPDATE balance=999 chưa commit, phiên B vẫn đọc được balance=100 (bản cũ) mà không bị chặn. Xem metadata ẩn xmin/xmax/ctid để hiểu vì sao UPDATE tạo phiên bản mới thay vì sửa tại chỗ.

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

Bốn mức cô lập giao dịch PostgreSQL: đọc bẩn, đọc lặp sai, phantom — đo thật từng cái

Mức cô lập giao dịch quyết định một giao dịch được thấy gì từ giao dịch khác đang chạy. Bài này đo thật trên pg-lab từng bất thường: ở Read Committed đọc cùng hàng hai lần ra 100 rồi 200 (đọc lặp sai), ở Repeatable Read vẫn 100 (an toàn). Và sự thật ít người biết: PostgreSQL không có đọc bẩn kể cả khi đặt Read Uncommitted.