10 kỹ thuật viết truy vấn bạn nên biết để tối ưu hóa query trong PostgreSQL
PostgreSQL là một hệ quản trị cơ sở dữ liệu mạnh mẽ và linh hoạt, nhưng nếu không tối ưu hóa truy vấn đúng cách, bạn sẽ gặp phải tình trạng truy vấn chậm, ngốn tài nguyên và hiệu suất giảm mạnh. Vậy làm sao để tối ưu hóa query trong PostgreSQL? Bài viết này sẽ chia sẻ 10 kỹ thuật thực tế giúp bạn cải thiện hiệu năng hệ thống nhanh chóng.
1. Sử dụng EXPLAIN để phân tích truy vấn#
Câu lệnh EXPLAIN cho biết PostgreSQL thực hiện truy vấn như thế nào: nó sử dụng chỉ mục hay quét toàn bộ bảng (Seq Scan), Join theo kiểu nào, chi phí ước lượng…
Ví dụ:#
EXPLAIN SELECT * FROM don_hang WHERE ngay >= '2024-01-01';
👉 Tối ưu dựa trên kết quả EXPLAIN là bước đầu tiên để hiểu vấn đề.
2. Tạo chỉ mục (Index) hợp lý#
Chỉ mục giúp truy vấn nhanh hơn, đặc biệt với các điều kiện lọc (WHERE), sắp xếp (ORDER BY), và join (ON). Nhưng đừng tạo quá nhiều chỉ mục không cần thiết – điều đó sẽ làm chậm các thao tác ghi (INSERT, UPDATE).
Gợi ý:#
Dùng B-Tree Index cho điều kiện
=,<,>.Dùng GIN Index cho tìm kiếm full-text.
Dùng partial index nếu chỉ lọc theo một phần dữ liệu.
3. Viết truy vấn có điều kiện cụ thể#
Tránh SELECT * hoặc các truy vấn không có WHERE, nhất là với bảng lớn.
✅ Tốt:
SELECT ten_khach_hang FROM don_hang WHERE trang_thai = 'hoan_thanh';
❌ Tệ:
SELECT * FROM don_hang;
4. Tránh subquery lồng nhau không cần thiết#
Thay vì lồng SELECT trong WHERE, hãy dùng JOIN hoặc WITH (CTE – Common Table Expression) nếu phù hợp.
Tránh:#
SELECT * FROM san_pham WHERE id IN (SELECT san_pham_id FROM khuyen_mai WHERE ngay > now());
Ưu tiên:#
SELECT sp.* FROM san_pham sp JOIN khuyen_mai km ON sp.id = km.san_pham_id WHERE km.ngay > now();
5. Dùng LIMIT khi truy vấn danh sách lớn#
Khi hiển thị kết quả tìm kiếm hay danh sách lớn, hãy dùng LIMIT kết hợp với OFFSET hoặc phân trang.
SELECT * FROM bai_viet ORDER BY ngay_dang DESC LIMIT 10 OFFSET 0;
6. Tối ưu JOIN và dùng đúng kiểu JOIN#
Sử dụng INNER JOIN thay vì LEFT JOIN nếu bạn chỉ cần dữ liệu có trong cả hai bảng.
Tránh JOIN bảng lớn nếu không cần thiết.
Đảm bảo các trường dùng JOIN có chỉ mục.
7. Phân vùng bảng (Partitioning)#
Khi bảng quá lớn, hãy cân nhắc chia nhỏ thành các partition dựa trên ngày, ID, khu vực… Điều này giúp truy vấn chỉ quét một phần nhỏ dữ liệu.
👉 Bạn có thể dùng native partitioning trong PostgreSQL từ phiên bản 10 trở lên.
8. Sử dụng Materialized View khi dữ liệu không thay đổi thường xuyên#
Nếu bạn có truy vấn phức tạp nhưng dữ liệu không thay đổi nhiều, hãy lưu kết quả thành Materialized View và cập nhật định kỳ:
CREATE MATERIALIZED VIEW top_san_pham AS SELECT san_pham_id, COUNT(*) as so_lan_mua FROM don_hang GROUP BY san_pham_id;
9. Giảm số lần truy cập cơ sở dữ liệu#
Thay vì chạy nhiều truy vấn nhỏ trong vòng lặp ứng dụng, hãy gom lại thành một truy vấn tổng hợp để giảm round-trip giữa app và DB.
10. Tối ưu cấu hình PostgreSQL (nâng cao)#
Nếu bạn kiểm soát được máy chủ, hãy tối ưu các tham số như:
work_mem– tăng để xử lý JOIN hoặc sort tốt hơnshared_buffers– tăng để PostgreSQL cache dữ liệu tốt hơneffective_cache_size– giúp PostgreSQL lên kế hoạch sử dụng bộ nhớ đệm hiệu quả hơn
Kết luận#
Tối ưu hóa truy vấn trong PostgreSQL không chỉ là việc tạo chỉ mục mà còn là cả quá trình phân tích, viết truy vấn thông minh và cấu hình hợp lý. Hãy bắt đầu bằng EXPLAIN, xác định điểm nghẽn và áp dụng dần các kỹ thuật trên.
✅ Nếu bạn đang quản lý hệ thống có nhiều truy vấn chậm hoặc dữ liệu lớn, hãy cho mình biết cấu trúc bảng hoặc câu truy vấn cụ thể, mình sẽ gợi ý tối ưu miễn phí!