Truy vấn MySQL bị chậm? Đây là cách giúp bạn tăng tốc x10 lần

❗ Vấn đề thường gặp – Câu truy vấn chậm:

Nhiều hệ thống MySQL gặp tình trạng truy vấn rất chậm dù chỉ cần lấy vài dòng dữ liệu (ví dụ: 6 sản phẩm nổi bật). Nguyên nhân phổ biến là vì câu truy vấn đang JOIN nhiều bảng lớn, sau đó mới ORDER BY và LIMIT, khiến MySQL phải xử lý hàng ngàn dòng trước rồi mới lọc ra vài dòng sau cùng. Điều này càng nghiêm trọng nếu bạn JOIN với các bảng VIEW, không có index hỗ trợ, hoặc dùng các điều kiện như != '' hoặc IS NOT NULL trên cột văn bản. Nếu không tối ưu, truy vấn tưởng chừng đơn giản có thể tiêu tốn hàng giây – đủ làm chậm toàn trang web hoặc API.

Câu truy vấn chậm

Ví dụ điền hình query Mysql:

SELECT p.product_id, p.product_name, p.price, p.date_added, c.category_name, b.brand_name 
FROM products AS p 
JOIN categories AS c ON p.category_id = c.category_id 
JOIN brands AS b ON p.brand_id = b.brand_id 
JOIN product_flags AS f ON f.product_id = p.product_id 
AND f.flag_type = "featured" 
WHERE p.status = "active" 
AND p.stock > 0 
ORDER BY f.date_added 
DESC LIMIT 6; 

Tại sao chậm?

  • Bảng products có hàng chục ngàn dòng.

  • JOIN 3 bảng: categories, brands, product_flags.

  • ORDER BY f.date_added DESC LIMIT 6 xảy ra sau khi JOIN, tức JOIN xong hàng ngàn dòng mới sắp xếp → rất tốn tài nguyên.

Hướng giải quyết: Truy vấn tối ưu

Truy vấn MySQL bị chậm? Đây là cách giúp bạn tăng tốc x10 lần
Truy vấn MySQL bị chậm? Đây là cách giúp bạn tăng tốc x10 lần

Chiến lược: Lấy danh sách product_id nổi bật LIMIT 6 trước, rồi mới JOIN thêm dữ liệu chi tiết.

✅ Truy vấn tối ưu:

SELECT p.product_id, p.product_name, p.price, p.date_added, c.category_name, b.brand_name 
FROM ( 
SELECT f.product_id 
FROM product_flags AS f 
JOIN products AS p ON f.product_id = p.product_id 
WHERE f.flag_type = "featured" 
AND p.status = "active" 
AND p.stock > 0 
ORDER BY f.date_added DESC 
LIMIT 6 
) AS top 
JOIN products AS p ON p.product_id = top.product_id 
JOIN categories AS c ON p.category_id = c.category_id 
JOIN brands AS b ON p.brand_id = b.brand_id;

Kết quả:

So sánh Truy vấn gốc Truy vấn tối ưu
JOIN trên Hàng ngàn dòng Chỉ 6 dòng
Chi phí ORDER BY Cực cao Rất nhẹ
Tốc độ Chậm Rất nhanh ⚡

Index đề xuất:

Trên bảng product_flags:

CREATE INDEX idx_flag_type_date ON product_flags(flag_type, date_added DESC, product_id); 

Trên bảng products:

CREATE INDEX idx_products_active ON products(status, stock, product_id); 

✅ Tóm gọn:

Vấn đề gốc:

ORDER BY ... LIMIT xảy ra sau JOIN → xử lý dữ liệu dư thừa

Giải pháp:

Tách bước LIMIT thành subquery nhỏ trước, rồi mới JOIN dữ liệu phụ

Nếu bạn đang làm PHP (CodeIgniter, Laravel…), bạn cũng có thể cache subquery đầu tiên (danh sách product_id nổi bật) trong 5 phút, sau đó dùng lại để JOIN nhanh hơn.

Kỹ thuật với database MySQL có thể bạn quan tâm

TAGS: mysql
About the Author

Tin liên quan