Za każdym razem, gdy napotykam na tego typu zapytania, zawsze zastanawiam się, jak by to zadziałał SQL Server. Jeśli uruchomię dowolny typ zapytania, który wymaga obliczenia, a następnie użyję tej wartości w wielu miejscach, na przykład w select
i order by
, czy SQL Server obliczy ją dwukrotnie dla każdego wiersza, czy będzie buforowana? Ponadto, jak to działa z funkcjami zdefiniowanymi przez użytkownika?
Przykłady:
SELECT CompanyId, Count(*)
FROM Sales
ORDER BY Count(*) desc
SELECT Geom.BufferWithTolerance(@radius, 0.01, 0).STEnvelope().STPointN(1).STX, Geom.BufferWithTolerance(@radius, 0.01, 0).STEnvelope().STPointN(1).STY
FROM Table
SELECT Id, udf.MyFunction(Id)
FROM Table
ORDER BY udf.MyFunction(Id)
Czy istnieje sposób, aby uczynić go bardziej wydajnym, czy też SQL Server jest wystarczająco inteligentny, aby go obsłużyć?
sql-server
Jonas Stawski
źródło
źródło
SELECT RAND() FROM Sales order by RAND()
- jest to oceniane tylko raz, ponieważ jest zarówno niedeterministyczne, jak i stała czasowa.Odpowiedzi:
Optymalizator zapytań SQL Server może łączyć powtarzane obliczone wartości w jednym operatorze obliczania skalarnego. To, czy to zrobi, zależy od kosztu planu zapytania i właściwości obliczonej wartości. Zgodnie z oczekiwaniami nie zrobi tego w przypadku wartości obliczeniowych, które nie są deterministyczne, z kilkoma wyjątkami takimi jak
RAND()
. Nie zrobi tego również w przypadku funkcji zdefiniowanych przez użytkownika.Zacznę od przykładu funkcji zdefiniowanej przez użytkownika. Oto doskonały przykład funkcji zdefiniowanej przez użytkownika:
Chcę również utworzyć tabelę i umieścić w niej 100 wierszy:
dbo.NULL_FUNCTION
Funkcja jest determistic. Ile razy będzie wykonywany dla następującego zapytania?Na podstawie planu zapytań zostanie to wykonane raz dla każdego wiersza lub 100 razy:
SQL Server 2016 wprowadził DMV sys.dm_exec_function_stats . Możemy zrobić migawki tego DMV, aby zobaczyć, ile razy UDF jest wykonywane przez zapytanie.
Wynikiem tego jest 100, więc funkcja została wykonana 100 razy.
Spróbujmy innego prostego zapytania:
Plan zapytań sugeruje, że funkcja zostanie wykonana 200 razy:
Wyniki
sys.dm_exec_function_stats
sugerują, że funkcja została wykonana 200 razy.Pamiętaj, że nie zawsze możesz użyć planu zapytań, aby dowiedzieć się, ile razy skalar obliczeniowy jest wykonywany. Poniższy cytat pochodzi z „ Obliczenia skalarów, wyrażeń i wydajności planu wykonania ”:
Spróbujmy innego przykładu. W przypadku następującego zapytania mam nadzieję, że UDF jest obliczany jeden raz:
Plan zapytań sugeruje, że zostanie obliczony jeden raz:
Jednak DMV ujawnia prawdę. Skalar obliczeniowy jest odraczany, dopóki nie jest potrzebny, czyli w operatorze łączenia. Jest oceniany 100 razy.
Zapytałeś również, co możesz zrobić, aby zachęcić optymalizator do unikania wielokrotnego ponownego obliczania tego samego wyrażenia. Najlepszą rzeczą, jaką możesz zrobić, to uniknąć skalarnego UDF w kodzie. Mają one szereg problemów z wydajnością poza tym pytaniem, w tym nadmuchiwanie przydziałów pamięci, zmuszanie do uruchomienia całego zapytania
MAXDOP 1
, złe oszacowanie liczności i prowadzące do dodatkowego wykorzystania procesora. Jeśli potrzebujesz użyć UDF, a wartość tego UDF jest stała, możesz obliczyć go poza zapytaniem i umieścić w zmiennej lokalnej.W przypadku zapytań bez UDF można spróbować uniknąć pisania wyrażeń, które zwracają ten sam wynik, ale nie są wpisywane dokładnie w ten sam sposób. W następnym przykładzie korzystam z publicznie dostępnej bazy danych AdventureworksDW2016CTP3, ale tak naprawdę każda baza danych będzie wystarczająca. Ile razy zostanie
COUNT(*)
obliczone dla tego zapytania?W przypadku tego zapytania możemy to zrozumieć, patrząc na operator dopasowania (agregacji) mieszania.
COUNT(*)
Jest obliczana raz dla każdej unikatowej wartościOrderDateKey
. DołączenieORDER BY
klauzuli nie powoduje dwukrotnego obliczenia. Można zobaczyć plan wykonania tutaj .Teraz rozważ zapytanie, które zwróci dokładnie te same wyniki, ale zostało napisane w inny sposób:
Optymalizator zapytań nie jest wystarczająco inteligentny, aby je połączyć, więc zostaną wykonane dodatkowe prace:
źródło