Type Mismatch và Implicit Cast - Cái bẫy ngầm trong MySQL

Lỗi cực kỳ phổ biến, rất khó phát hiện, đặc biệt trong dự án chạy lâu năm.

Tình huống

-- Schema: cột payment_id kiểu VARCHAR(255)
-- Query tìm đơn hàng theo payment ID:
SELECT * FROM orders WHERE payment_id = 57013925718;
--                                      ↑ KHÔNG có dấu nháy → kiểu số

Có index trên payment_id nhưng query chậm không tưởng. Lý do:

Cột payment_id:  VARCHAR(255)  ← kiểu chuỗi
Giá trị so sánh: 57013925718   ← kiểu số nguyên
 
Hai kiểu khác nhau → MySQL phải chuyển đổi một bên.
Bạn nghĩ MySQL chuyển số → chuỗi? KHÔNG!
MySQL LUÔN chuyển CHUỖI → SỐ khi so sánh hỗn hợp.
 
MySQL ngầm viết lại query thành:
SELECT * FROM orders WHERE CAST(payment_id AS UNSIGNED) = 57013925718;
                           ↑ CỘT bị biến đổi → index VÔ DỤNG!

Vì cột bị áp hàm CAST()Column Transformation → database quét toàn bộ bảng, chuyển đổi từng giá trị rồi so sánh.

Sửa rất đơn giản: thêm dấu nháy

-- ✅ Đúng kiểu: chuỗi so sánh với chuỗi
SELECT * FROM orders WHERE payment_id = '57013925718';

Chiều ngược lại thì KHÔNG SAO

-- Cột age kiểu INT, giá trị so sánh kiểu chuỗi
SELECT * FROM users WHERE age = '25';
-- MySQL chuyển '25' → 25 (chuyển đổi trên GIÁ TRỊ, không phải trên CỘT)
-- → Index vẫn hoạt động bình thường

Quy tắc: vấn đề chỉ xảy ra khi CỘT là chuỗi nhưng giá trị so sánh là số.

Mẹo phòng tránh

Khi thấy cột VARCHAR lưu giá trị trông giống số (mã giao dịch, mã vận đơn, số điện thoại) → luôn luôn dùng dấu nháy trong query. Tốt nhất: kiểm tra toàn bộ codebase xem có chỗ nào truyền số nguyên vào cột chuỗi không - đặc biệt các query sinh tự động bởi ORM hoặc query builder.

Liên quan