SQL er et deklarativt sprog, ikke et proceduresprog. Det vil sige, at du konstruerer en SQL-sætning til at beskrive de resultater, du ønsker. Du fortæller ikke SQL-motoren hvordan at gøre arbejdet.
Som hovedregel er det en god idé at lade SQL-motoren og SQL-optimeringsværktøjet finde den bedste forespørgselsplan. Der er mange års indsats, der går til at udvikle en SQL-motor, så lad ingeniørerne gøre, hvad de ved, hvordan de skal gøre.
Selvfølgelig er der situationer, hvor forespørgselsplanen ikke er optimal. Så vil du bruge forespørgselstip, omstrukturere forespørgslen, opdatere statistik, bruge midlertidige tabeller, tilføje indekser og så videre for at få bedre ydeevne.
Med hensyn til dit spørgsmål. Ydeevnen af CTE'er og underforespørgsler bør i teorien være den samme, da begge giver den samme information til forespørgselsoptimeringsværktøjet. En forskel er, at en CTE brugt mere end én gang let kunne identificeres og beregnes én gang. Resultaterne kan derefter gemmes og læses flere gange. Desværre ser SQL Server ikke ud til at drage fordel af denne grundlæggende optimeringsmetode (du kan kalde denne almindelige underforespørgseleliminering).
Midlertidige tabeller er en anden sag, fordi du giver mere vejledning om, hvordan forespørgslen skal køres. En stor forskel er, at optimeringsværktøjet kan bruge statistik fra den midlertidige tabel til at etablere sin forespørgselsplan. Dette kan resultere i præstationsgevinster. Desuden, hvis du har en kompliceret CTE (underforespørgsel), der bruges mere end én gang, så vil lagring af den i en midlertidig tabel ofte give et ydelsesboost. Forespørgslen udføres kun én gang.
Svaret på dit spørgsmål er, at du skal spille rundt for at få den ydeevne, du forventer, især for komplekse forespørgsler, der køres på regelmæssig basis. I en ideel verden ville forespørgselsoptimeringsværktøjet finde den perfekte eksekveringssti. Selvom det ofte gør det, kan du muligvis finde en måde at få bedre ydeevne på.