MySQL har kända problem med optimeringsfrågor som involverar korrelerade delfrågor, eller underval. Fram till version 5.6.5 materialiseras det inte underfrågor, men det kommer att materialiseras en härledd tabell som används i en join.
I huvudsak betyder detta att när du använder en join kommer MySQL att utföra följande första gången underfrågan påträffas:
SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1
Och behåll resultaten i en tillfällig tabell (som hashas för att göra uppslagningar snabbare), sedan för varje värde i myTable
den kommer att slå upp mot den temporära tabellen för att se om koden finns där.
Men sedan när du använder IN
underfrågan materialiseras inte och skrivs om som:
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
)
Vilket betyder att för varje code
i myTable
, kör den underfrågan igen. Vilket när din yttre fråga är mycket smal är bra, eftersom det är mer effektivt att bara köra underfrågan ett fåtal gånger, än att köra den för alla värden och lagra resultaten i en temporär tabell, men när din yttre fråga är bred, resulterar det i i den inre frågan som körs många gånger, och det är här prestandaskillnaden börjar.
Så för dina radräkningar, istället för att köra underfrågan ~30 000 gånger, kör du den en gång och slår sedan upp ~30 000 rader mot en hashad temporär tabell med bara 400 rader in. Detta skulle svara för en så drastisk prestandaskillnad.
Den här artikeln i onlinedokumentationen förklarar subquery optimering mycket mer djupgående.