Assicurati di svuotare l'esecuzione + la cache dei dati tra ogni esecuzione di test.
es.
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
Se si esegue prima con UNION ALL, e poi si eseguono separatamente le 2 selezioni, i dati saranno già memorizzati nella cache rendendo le prestazioni molto migliori (dando quindi la falsa impressione che l'approccio successivo sia più rapido quando potrebbe non esserlo).
Se hai usato UNION, potrebbe essere più lento in quanto deve applicare un DISTINCT, ma UNION ALL non deve farlo, quindi non dovrebbe essere diverso.
Aggiornamento:
Dai un'occhiata ai piani di esecuzione e confrontali:vedi se c'è qualche differenza. Puoi visualizzare il piano di esecuzione facendo clic sul pulsante "Includi piano di esecuzione effettivo" in SSMS prima di eseguire la query
Aggiornamento 2:
Sulla base dei CTE completi forniti, penso che cercherei di ottimizzarli:non credo che UNION ALL sia effettivamente il problema.
IMHO, la cosa migliore da provare è lavorare attraverso i CTE uno per uno e provare a ottimizzarli individualmente in modo che quando li combini tutti nella query principale, funzionino meglio.
per esempio. per tDictionaryStreets, che ne dici di provare questo:
SELECT DISTINCT
r.KladrItemName AS RegionName,
a.KladrItemName AS AreaName,
c.KladrItemName AS CityName,
sc.KladrItemName AS SubCityName,
s.StreetName
FROM StreetNames s
JOIN tFoundStreets fs ON s.StreetName = fs.KladrItemName
LEFT JOIN tFoundRegions r ON s.RegionName = r.KladrItemName
LEFT JOIN tFoundAreas a ON s.AreaName = a.KladrItemName
LEFT JOIN tFoundCities c ON s.CityName = c.KladrItemName
LEFT JOIN tFoundSubCities sc ON s.SubCityName = scc.KladrItemName
KladrItemName su ogni tabella dovrebbe avere almeno un indice attivo. Prova a rielaborare tDictionarySubCities allo stesso modo anche con i join.