Subquery - Không chậm như bạn nghĩ
“Subquery chậm” là thiên kiến phổ biến. Chúng chậm vì THIẾU INDEX, không phải vì bản chất của subquery.
Independent Subquery
Chạy 1 lần duy nhất, kết quả thay thế vào query chính:
SELECT * FROM products
WHERE remaining > 500 AND category_id = (
SELECT category_id FROM categories
WHERE type = 'book' AND name = 'Science fiction'
);
-- Index cho subquery: (type, name) trên categories
-- Index cho outer query: (category_id, remaining) trên productsDependent Subquery
Chạy lặp lại cho mỗi row - giống join (Nested Loop Join):
SELECT * FROM products
WHERE remaining = 0 AND EXISTS (
SELECT * FROM sales
WHERE created_at >= '2023-01-01' AND product_id = products.product_id
);
-- Index cho outer: (remaining) trên products
-- Index cho subquery: (product_id, created_at) trên salesTip: EXISTS tự động dừng sau khi tìm thấy 1 row match (giống có LIMIT 1 ngầm). Nhưng vẫn nên tạo index theo nguyên tắc range condition để tối ưu.
Nguyên tắc chung
Xem mỗi subquery như một query độc lập cần index riêng - giống hệt tư duy với join: phân tách, tạo index cho từng phần.
Liên quan
- Nested Loop Join - dependent subquery = loop
- CTE - cách tách query phức tạp dễ debug hơn nested subquery
- Range Condition phá vỡ Phễu - thứ tự cột trong index của subquery