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 được

Cá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