Upewnij się, że wyczyściłeś pamięć podręczną wykonania + danych między każdym testem.
np.
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
Jeśli najpierw uruchomisz UNION ALL, a następnie uruchomisz 2 wybory osobno, dane będą już buforowane w pamięci, co znacznie poprawia wydajność (co daje fałszywe wrażenie, że kolejne podejście jest szybsze, gdy może nie być).
Jeśli użyłeś UNION, może to być wolniejsze, ponieważ musi zastosować DISTINCT, ale UNION ALL nie musi tego robić, więc nie powinno być inaczej.
Aktualizacja:
Spójrz na plany wykonania i porównaj je - zobacz, czy jest jakaś różnica. Możesz wyświetlić plan wykonania, klikając przycisk "Uwzględnij rzeczywisty plan wykonania" w SSMS przed uruchomieniem zapytania
Aktualizacja 2:
Na podstawie podanych pełnych CTE myślę, że chciałbym je zoptymalizować - nie sądzę, aby UNION ALL był w rzeczywistości problemem.
IMHO, najlepszą rzeczą do wypróbowania jest przechodzenie przez CTE jeden po drugim i próba zoptymalizowania każdego z nich z osobna, aby po połączeniu ich wszystkich w głównym zapytaniu działały lepiej.
np. dla tDictionaryStreets, co powiesz na wypróbowanie tego:
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 w każdej tabeli powinien mieć przynajmniej indeks. Spróbuj przerobić tDictionarySubCities w ten sam sposób z połączeniami.