Inequality (!=) và Index - Kẻ giết hiệu suất thầm lặng
Điều kiện != là một trong những thứ tệ nhất cho index.
SELECT * FROM payments WHERE status != 'open';
-- Index (status):
-- [cancelled | cancelled | open | open | open | paid | paid | refunded]
-- ✅ ✅ ❌ ❌ ❌ ✅ ✅ ✅
-- → Kết quả match nằm ở CẢ HAI PHÍA của 'open'
-- → Không phải range scan (một hướng) → phải đọc TẤT CẢ
-- → Chẳng khác gì full table scan!Tệ hơn: database không thể dự đoán bao nhiêu row match != 'open' (có thể 5% hoặc 95%) → cost model không đánh giá được → thường fallback về full table scan luôn.
3 cách xử lý
Cách 1: Kết hợp thêm cột equality thu hẹp phạm vi (đơn giản, hiệu quả nhất)
SELECT * FROM payments WHERE shop_id = 42 AND status != 'open';
-- Index: (shop_id, status)
-- 1. Fast lookup shop_id=42 → thu hẹp xuống vài trăm entries
-- 2. Scan trong phạm vi đó, filter status != 'open'
-- → Database chấp nhận dùng index vì biết chắc upper bound → cost tính đượcCách 2: Chuyển inequality thành IN(…) nếu biết trước giá trị
-- status chỉ có: 'open', 'paid', 'cancelled', 'refunded'
-- Thay vì: WHERE status != 'open'
WHERE status IN ('paid', 'cancelled', 'refunded')
-- → Database tách thành 3 equality lookups, hiệu quả hơn nhiều!Cách 3: Chuyển thành boolean column / functional index
CREATE INDEX payments_not_open ON payments ((status != 'open'));
-- Sau đó: WHERE (status != 'open') = true → equality check!Liên quan
- Fast Lookup - vì sao equality mạnh hơn inequality
- NULL và Index - NULL trong so sánh != còn gây bug logic
- Functional Index - nền tảng của cách 3
- Query Optimizer và Cost Model - vì sao optimizer bỏ cuộc với !=