MySQL har kendte problemer med optimeringsforespørgsler, der involverer korrelerede underforespørgsler eller undervalg. Indtil version 5.6.5 materialiserer det ikke underforespørgsler, men det vil materialisere en afledt tabel, der bruges i en join.
I bund og grund betyder dette, at når du bruger en joinforbindelse, vil MySQL udføre følgende første gang underforespørgslen stødes på:
SELECT code1 FROM myTable GROUP BY code1 HAVING COUNT(code1) > 1
Og hold resultaterne i en midlertidig tabel (som er hashed for at gøre opslag hurtigere) og derefter for hver værdi i myTable
den vil slå op mod den midlertidige tabel for at se, om koden er der.
Men siden da bruger du IN
underforespørgslen er ikke materialiseret og er omskrevet 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
)
Hvilket betyder, at for hver code
i myTable
, kører den underforespørgslen igen. Hvilket når din ydre forespørgsel er meget smal er fint, da det er mere effektivt kun at køre underforespørgslen et par gange, end at køre den for alle værdier og gemme resultaterne i en midlertidig tabel, men når din ydre forespørgsel er bred, resulterer det i i den indre forespørgsel, der udføres mange gange, og det er her, præstationsforskellen starter.
Så for dine rækketællinger, i stedet for at køre underforespørgslen ~30.000 gange, kører du den én gang og slår derefter ~30.000 rækker op mod en hashed midlertidig tabel med kun 400 rækker i. Dette ville tage højde for en så drastisk forskel i ydeevne.
Denne artikel i onlinedokumenterne forklarer optimering af underforespørgsler i meget mere dybde.