LIKE và Wildcard - “Cái bẫy” ký tự đại diện ở đầu

LIKE 'Nguyễn%' dùng được index (chuyển thành range scan). LIKE '%Nguyễn%' thì KHÔNG.

LIKE prefix = range condition

-- LIKE 'Nguyễn%' tương đương:
WHERE firstname >= 'Nguyễn' AND firstname < 'Nguyễo'
-- (Nguyễo = ký tự kế tiếp sau 'n' trong bảng mã)

Vì là range condition, nó tuân theo Nguyên tắc 4: cột LIKE nên đặt sau các equality columns:

WHERE type = 'customer' AND firstname LIKE 'Nguyễn%';
-- ✅ (type, firstname): type equality → phễu, firstname LIKE → range scan
-- ❌ (firstname, type): firstname LIKE → range scan ngay, type chỉ filter

Wildcard ở giữa (LIKE 'Nguyễn%s') vẫn dùng được index: tìm range Nguyễn..Nguyễo rồi filter pattern %s trên kết quả.

Leading wildcard: không dùng được B-tree index

WHERE name LIKE '%Nguyễn%';  -- Database KHÔNG thể dùng B-tree index!

%Nguyễn% match bất cứ vị trí nào trong string - ‘Tên tôi là Nguyễn Văn A’, ‘xNguyễn123’… chúng rải rác khắp nơi trong sorted list, database không biết bắt đầu scan từ đâu. Cost model cũng không ước lượng được số rows match → fallback full table scan.

Giải pháp cho leading wildcard

  • PostgreSQL: Trigram Index (pg_trgm + GIN)
  • MySQL: KHÔNG có giải pháp built-in. Cân nhắc Full-Text Search (MATCH AGAINST) hoặc external search engine (Elasticsearch, MeiliSearch) cho use case search phức tạp.

Liên quan