Column Transformation - Sai lầm #1 khiến index bị “mù”
Bất kỳ phép biến đổi nào áp dụng LÊN CỘT (không phải lên giá trị) đều khiến index vô dụng.
-- ❌ Hàm trên cột → index trên birthday VÔ DỤNG
SELECT * FROM contacts WHERE YEAR(birthday) = 1988;
-- Database thấy: YEAR(birthday) là một biểu thức, không phải cột birthday
-- Index lưu '1988-03-15', '1990-07-22'... không phải 1988, 1990 → không map được!
-- ✅ Viết lại: dùng range condition trên cột gốc
SELECT * FROM contacts
WHERE birthday >= '1988-01-01' AND birthday < '1989-01-01';Tại sao database không tự rewrite? Vì phải xử lý mọi tổ hợp hàm có thể - cực phức tạp và dễ sai. Nguyên tắc giữ đơn giản: biến đổi cột = không dùng index. Không ngoại lệ.
Các trường hợp hay gặp
❌ WHERE col + 5 < 20 → ✅ WHERE col < 15
❌ WHERE CONCAT(first,' ',last)='Huy Nguyen' → ✅ WHERE first='Huy' AND last='Nguyen'
❌ WHERE varchar_col = 12345 (type juggling) → ✅ WHERE varchar_col = '12345'
❌ WHERE DATE(created_at) = '2024-01-15'
→ ✅ WHERE created_at >= '2024-01-15' AND created_at < '2024-01-16'
❌ WHERE LOWER(email) = '[email protected]' → ✅ Dùng functional indexQuy tắc phân biệt
Biến đổi trên GIÁ TRỊ thì an toàn (database tính trước rồi so sánh); biến đổi trên CỘT thì phá index. WHERE age = '25' với age INT vẫn ổn - MySQL chuyển ‘25’ → 25 trên giá trị.
Khi KHÔNG THỂ viết lại query
WHERE MONTH(birthday) = 5 (tháng 5 của mọi năm) không thể chuyển thành range → dùng Functional Index.
Liên quan
- Functional Index - giải pháp khi không viết lại được
- Type Mismatch và Implicit Cast - trường hợp đặc biệt nguy hiểm của column transformation
- Query Optimizer và Cost Model - checklist debug index bị bỏ qua