MySQL има известни проблеми с оптимизиране на заявки, включващи корелирани подзаявки или подселекции. До версия 5.6.5 той не материализира подзаявки, но ще материализира производна таблица, използвана в обединяване.
По същество това означава, че когато използвате присъединяване, първия път, когато се срещне подзаявката, MySQL ще изпълни следното:
SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1
И запазете резултатите във временна таблица (която е хеширана, за да направи търсенията по-бързи), след това за всяка стойност в myTable
той ще търси във временната таблица, за да види дали кодът е там.
Въпреки това, откакто използвате IN
подзаявката не се материализира и се пренаписва като:
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
)
Което означава, че за всеки code
в myTable
, стартира отново подзаявката. Което, когато външната ви заявка е много тясна, е добре, тъй като е по-ефективно да стартирате подзаявката само няколко пъти, отколкото да я стартирате за всички стойности и да съхранявате резултатите във временна таблица, но когато външната ви заявка е широка, това води до във вътрешната заявка, изпълнявана много пъти, и тук се появява разликата в производителността.
Така че за броя на вашите редове, вместо да изпълнявате подзаявката ~30 000 пъти, я стартирате веднъж, след което търсите ~30 000 реда срещу хеширана временна таблица само с 400 реда. Това би обяснило толкова драстична разлика в производителността.
Тази статия в онлайн документи обяснява оптимизацията на подзаявки много по-задълбочено.