Composite index (index nhiều cột) giống danh bạ sắp theo "họ rồi tên": tra theo họ rất nhanh, nhưng tra chỉ theo tên thì gần vô dụng. Đây là quy tắc tiền tố trái (leftmost prefix):
Index (a, b, c) dùng được cho lọc trên (a), (a,b), (a,b,c) — nhưng KHÔNG dùng được cho riêng (b), riêng (c), hay (b,c) vì thiếu cột đầu.
Ví dụ: index (status, created_at) — query WHERE status = 'active' ORDER BY created_at dùng trọn vẹn; còn WHERE created_at > '2024-01-01' thì không, vì bỏ qua status.
Thứ tự cột tối ưu:
1. Cột lọc bằng (=) đặt trước.
2. Cột khoảng (>, <, BETWEEN) đặt sau.
3. Cột ORDER BY đặt cuối — vì sau một điều kiện khoảng, index không còn giúp sắp xếp.
Ví dụ: WHERE user_id = ? AND status = ? AND created_at > ? → index (user_id, status, created_at).
Lưu ý: (a, b) và (b, a) là hai index khác nhau, phục vụ pattern query khác nhau — đừng nhầm là một.
A composite index (multi-column index) is like a phone book sorted by "last name then first name": looking up by last name is fast, but by first name alone is nearly useless. This is the leftmost-prefix rule:
An index (a, b, c) works for filters on (a), (a,b), (a,b,c) — but NOT for (b) alone, (c) alone, or (b,c), because the leading column is missing.
Example: index (status, created_at) — the query WHERE status = 'active' ORDER BY created_at uses it fully; but WHERE created_at > '2024-01-01' does not, because it skips status.
Optimal column order:
1. Equality (=) columns first.
2. Range columns (>, <, BETWEEN) next.
3. ORDER BY columns last — because after a range condition the index can no longer help sorting.
Example: WHERE user_id = ? AND status = ? AND created_at > ? → index (user_id, status, created_at).
Pitfall: (a, b) and (b, a) are two different indexes serving different query patterns — don't treat them as the same.