Bắt đầu từ query plan, rồi sửa cái tốn kém nhất. Dùng EXPLAIN/ để xem database thực sự làm gì, thêm đúng, loại bỏ query , và chỉ select dữ liệu bạn cần.
Bắt đầu từ query plan, rồi sửa cái tốn kém nhất. Dùng EXPLAIN/ để xem database thực sự làm gì, thêm đúng, loại bỏ query , và chỉ select dữ liệu bạn cần.
EXPLAIN ANALYZEEXPLAIN ANALYZE cho thấy execution plan và thời gian thực. Một Seq Scan trên bảng lớn là dấu hiệu báo động kinh điển:
EXPLAIN ANALYZE
SELECT * FROM orders WHERE customer_id = 42;
-- Seq Scan on orders (cost=0.00..18500 rows=120)
-- Filter: (customer_id = 42)
-- rows removed by filter: 999880 ← quét cả bảng!
Một index biến full scan thành lookup nhanh:
CREATE INDEX idx_orders_customer ON orders (customer_id);
-- Bây giờ: Index Scan using idx_orders_customer (cost=0.42..8.5 rows=120)
-- quét 1,000,000 dòng → lookup ~120 dòng
Index có chi phí lên ghi: mỗi INSERT/UPDATE cũng phải cập nhật index, nên hãy đánh index các cột bạn filter/join/sort — không phải mọi cột. Một index composite (customer_id, created_at) phục vụ WHERE customer_id = ? ORDER BY created_at trong một cấu trúc.
Vấn đề N+1 — một query cho danh sách, rồi một query cho mỗi dòng — là nguyên nhân hàng đầu gây chậm. Thay nó bằng eager loading, một JOIN, hoặc IN (...) theo lô:
-- N+1: 1 + 100 query
SELECT * FROM orders; -- rồi mỗi order: SELECT * FROM users WHERE id = ?
-- Đã sửa: một JOIN, chỉ các cột cần
SELECT o.id, o.total, u.name
FROM orders o JOIN users u ON u.id = o.user_id;
Ngoài ra hãy chỉ select các cột cần (tránh SELECT *) và phân trang bằng LIMIT/keyset pagination để không bao giờ tải hàng triệu dòng.
Database là bottleneck phổ biến nhất. Đọc plan cho bạn biết vì sao một query chậm thay vì đoán; index đúng, loại bỏ N+1, và cắt gọn tập kết quả thường biến query dài cả giây thành query vài mili-giây — mà không cần scale phần cứng.