MySQL có sự cố đã biết với việc tối ưu hóa các truy vấn liên quan đến các truy vấn con tương quan hoặc các lựa chọn con. Cho đến phiên bản 5.6.5, nó không hiện thực hóa các truy vấn con, tuy nhiên, nó sẽ hiện thực hóa một bảng dẫn xuất được sử dụng trong một phép nối.
Về bản chất, điều này có nghĩa là khi bạn sử dụng phép nối, lần đầu tiên truy vấn con gặp MySQL sẽ thực hiện như sau:
SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1
Và giữ kết quả trong một bảng tạm thời (được băm để giúp tra cứu nhanh hơn), sau đó cho từng giá trị trong myTable
nó sẽ tra cứu bảng tạm thời để xem mã có ở đó không.
Tuy nhiên, kể từ khi bạn sử dụng IN
truy vấn con không được hiện thực hóa và được viết lại như sau:
SELECT t1.code1, t1.code2
FROM myTable t1
WHERE EXISTS
( SELECT t2.code1
FROM myTable t2
WHERE t2.Code1 = t1.Code1
GROUP BY t2.code1
HAVING COUNT(t2.code1) > 1
)
Có nghĩa là đối với mỗi code
trong myTable
, nó chạy lại truy vấn con. Điều này khi truy vấn bên ngoài của bạn rất hẹp cũng không sao, vì chỉ chạy truy vấn con một vài lần sẽ hiệu quả hơn là chạy nó cho tất cả các giá trị và lưu trữ kết quả trong một bảng tạm thời, tuy nhiên, khi truy vấn bên ngoài của bạn rộng, kết quả là trong truy vấn bên trong thực thi nhiều lần và đây là lý do tạo ra sự khác biệt về hiệu suất.
Vì vậy, đối với số lượng hàng của bạn, thay vì chạy truy vấn con ~ 30.000 lần, bạn chạy truy vấn đó một lần, sau đó tra cứu ~ 30.000 hàng so với bảng tạm thời đã băm chỉ có 400 hàng. Điều này sẽ giải thích cho sự khác biệt về hiệu suất nghiêm trọng như vậy.
Bài viết này trong tài liệu trực tuyến giải thích sâu hơn về tối ưu hóa truy vấn con.