Hai câu cho cùng kết quả. Một chạy 0,1 giây, một chạy 3 giây. Khác nhau ở một từ khoá.
Bài toán
Tìm khách hàng đã từng đặt ít nhất một đơn. Ba cách viết đều đúng, nhưng chi phí rất khác nhau.
Ba cách
-- 1. IN
SELECT * FROM khach_hang
WHERE id IN (SELECT khach_hang_id FROM don_hang);
-- 2. EXISTS
SELECT * FROM khach_hang k
WHERE EXISTS (SELECT 1 FROM don_hang d WHERE d.khach_hang_id = k.id);
-- 3. JOIN + DISTINCT
SELECT DISTINCT k.* FROM khach_hang k
JOIN don_hang d ON d.khach_hang_id = k.id;
Khác biệt cốt lõi
EXISTS dừng ngay khi tìm thấy dòng đầu tiên. Một khách có 500 đơn thì nó vẫn chỉ đọc một dòng. IN phải dựng xong toàn bộ danh sách bên trong rồi mới so.
JOIN + DISTINCT tệ nhất: nó nhân bản 500 dòng rồi mới khử trùng lặp.
EXISTS. Cần lấy cột từ bảng bên phải thì mới dùng JOIN. Danh sách ngắn cố định thì IN đọc dễ hơn.
Lỗi thường gặp
1. NOT IN gặp NULL
-- Trả về RỖNG nếu bảng con có một NULL
WHERE id NOT IN (SELECT khach_hang_id FROM don_hang);
-- Luôn an toàn
WHERE NOT EXISTS (SELECT 1 FROM don_hang d WHERE d.khach_hang_id = k.id);
2. Viết SELECT * trong EXISTS
SELECT 1 hay SELECT * đều như nhau về hiệu năng — bộ tối ưu hoá bỏ qua danh sách cột. Nhưng SELECT 1 nói rõ ý định: “tôi không lấy dữ liệu, tôi chỉ kiểm tra”.
3. Quên điều kiện liên kết
-- Luôn đúng với mọi khách, vì bảng con không phụ thuộc k
WHERE EXISTS (SELECT 1 FROM don_hang);
EXISTS phải là subquery tương quan — bên trong bắt buộc tham chiếu tới bảng bên ngoài.
Luyện tập
- LeetCode 1050 — Actors and Directors Who Cooperated At Least Three Times
- LeetCode 1148 — Article Views I
- LeetCode 1517 — Find Users With Valid E-Mails
- LeetCode 619 — Biggest Single Number
Tóm lại
EXISTSdừng ở dòng đầu tiên tìm thấy;INdựng hết danh sách.- Kiểm tra tồn tại thì dùng
EXISTS, lấy dữ liệu thì dùngJOIN. NOT INgặpNULLtrả về rỗng — luôn thay bằngNOT EXISTS.JOIN + DISTINCTlà cách chậm nhất trong ba cách.EXISTSphải tham chiếu tới bảng bên ngoài mới có nghĩa.
Bạn vừa học xong EXISTS và IN
Sẵn sàng luyện tập chưa?
Làm bài tập EXISTS và IN trên dữ liệu thật, chấm điểm ngay khi bạn bấm chạy.
Bắt đầu luyện tập →