Biến Range thành Equality (Biến đổi điều kiện phạm vi)

Nếu biến range condition thành so sánh bằng, hạn chế “range phá vỡ phễu” biến mất.

Bài toán

SELECT * FROM repos
WHERE language = 'TypeScript' AND stars > 1000
ORDER BY sponsors ASC;
 
-- Phương án 1: Index (language, stars, sponsors)
--   → range bắt đầu ở stars → sponsors KHÔNG được sắp xếp liên tục
--   → phải sắp xếp lại sau khi lấy kết quả (filesort)
-- Phương án 2: Index (language, sponsors) bỏ qua stars
--   → sort đúng nhưng phải quét toàn bộ TypeScript rồi lọc stars
-- Cả hai đều không lý tưởng!

Ý tưởng: thay vì hỏi “bao nhiêu sao?” → hỏi “có phổ biến không?” (0 hoặc 1)

-- Tạo index trên biểu thức boolean
CREATE INDEX repos_search ON repos (
    language,
    (IF(stars > 1000, 1, 0)),  -- boolean: phổ biến hay không
    sponsors                    -- sắp xếp
);
 
-- Query dùng đúng biểu thức
SELECT * FROM repos
WHERE language = 'TypeScript'
  AND IF(stars > 1000, 1, 0) = 1
ORDER BY sponsors ASC;
 
-- Phễu hoạt động hoàn hảo:
-- Bước 1: language = 'TypeScript' (equality)
-- Bước 2: is_popular = 1          (equality)
-- Bước 3: đọc theo sponsors tăng dần (đã sắp xếp sẵn!) → KHÔNG cần filesort

Khi nào dùng kỹ thuật này?

Khi query có cả lọc range lẫn sắp xếp, và điều kiện range có thể rút gọn thành “có/không” theo logic nghiệp vụ:

  • “giá trên 100k” → is_expensive
  • “đăng ký trên 1 năm” → is_veteran
  • “đánh giá trên 4 sao” → is_highly_rated

Kỹ thuật này cũng cứu GROUP BY + WHERE range: tạo cột age_group='twenties' rồi WHERE age_group='twenties' → equality → phễu tiếp tục hoạt động.

Liên quan