Vì index lưu giá trị gốc của cột, không lưu kết quả của hàm.
- Khi cột bị bọc trong một hàm, database phải tính hàm đó cho từng dòng rồi mới so sánh — nghĩa là phải đọc hết bảng.
- Điều kiện như vậy gọi là non-sargable (không dùng được làm access predicate).
sql
-- non-sargable: forces a full scan
SELECT * FROM orders WHERE DATE(created_at) = '2026-01-01';
-- sargable: half-open range, index on created_at is usable
SELECT * FROM orders
WHERE created_at >= '2026-01-01'
AND created_at < '2026-01-02';Cùng lỗi này còn xuất hiện ở nhiều dạng khác:
- WHERE YEAR(created_at) = 2026 → đổi thành khoảng >= '2026-01-01' AND < '2027-01-01'.
- WHERE amount * 100 > 5000 → chuyển phép tính sang vế hằng số: amount > 50.
- WHERE UPPER(email) = 'A@B.COM' → chuẩn hoá dữ liệu khi ghi, hoặc dùng expression index.
Dùng khoảng nửa mở (>= và <) thay vì BETWEEN khi cột là timestamp: BETWEEN '2026-01-01' AND '2026-01-02' sẽ lấy lẫn đúng thời điểm nửa đêm ngày hôm sau.