Ofta ser man sqler som använder sig av IN() på ett eller annat sätt. Tex:
Select Id from tblA where Id IN(Select Id from tblB)
Visst är det smidigt, det många dock inte vet är att IN() kan vara en riktig prestandaätare. Jag tänkte därför visa en alternativ lösning som ger exakt samma resultat och även presentera lite prestandaskillnader. Istället för IN() kan vi använda oss av en helt vanlig Inner Join, och istället för Not IN() så kan vi använda oss av en Left Join och sedan kontrollera ifall en post saknas eftersom vi då får Null-resultat om det inte finns någon relaterad post.
Sqlen som jag visade i början skulle alltså även kunna skrivas såhär för att ge samma resultat:
Select Distinct tblA.Id From tblA Inner Join tblB On tblA.Id = tblB.Id
Vi måste förutom att lägga till en Inner Join även lägga till en Distinct, eftersom vi bara vill ha ut en post från tblA och inte en post för varje relaterad post som finns i tblB.
Båda Sqlerna kommer alltså att plocka ut posterna från tblA där det finns en relaterad post i tblB. Skillnaden är dock prestandan.
Jag körde de båda frågorna på en mssql 2000 databas via SQL Query Analyzer för att kunna se hur lång tid den behövde för att köra frågorna. Både tabellen A och B hade ungefär 150 000 poster i sig.
Den sqlen som använde sig av IN() tog exakt 2 minuter och 19 sekunder att köra. Den sqlen som istället använde sig av en Inner Join tog 1 minut och 35 sekunder. Man kan sen lista ut att om man har stora frågor, mer komplexa, med flera IN() så kommer självklart prestandaskillnaden bli ännu större mellan dessa två sqler.
Jag vill dock poängtera att det enbart är Select i IN() som man ska undvika. Skickar man in hårda id-nummer till databasen så fungerar det utmärkt (tex: IN(1,43,24)). Det är också viktigt att det här testet inte ses som vetenskapligt på något sätt. Utan med rätt indexering, cache etc så är det möjligt att man kan få helt andra siffror.