SQL Server 2019 – Intelligent Query Processing – Scalar Function Inlining

SQLServer_ScalarFunctionInline_00

Premiera SQL Server 2019 za nami, a wraz z nią pojawił się cały szereg nowych funkcjonalności. Jedną z nich jest rozszerzenie koncepcji Adaptive Query Processing czyli zestawu technologii, które umożliwiają dostosowanie sposobu wykonania zapytania podczas jego wykonania. Obecnie cała rodzina tych technologii nazywana jest Intelligent Query Processing, a jej schemat poglądowy możecie zobaczyć na poniższej grafice:

Część z tych funkcjonalności zdołałem już opisać w ramach krótkiej serii trzech artykułów poświęconych Adaptive Query Processing (jeśli ktoś nie jest z nimi zaznajomiony linki poniżej):

Dziś chciałbym poszerzyć nieco całą koncepcję i opisać kolejną funkcjonalność, którą jest TSQL Scalar UDF Inlining.

O tym jak dużym problemem były skalarne funkcje użytkownika raczej nie trzeba mówić. W wielu przypadkach wydajność była niewystarczająca z powodu problemu z wielowątkowością. Pokażmy to na konkretnym przykładzie, na wstępie ustawimy cost treshold of parallelism na 0 tzn. każde zapytanie będzie rozpatrywane jako wielowątkowe:

W dalszej kolejności użyjemy bazy WideWorldImportersDW i zmienimy jej Compatibility Level na 140 (czyli zgodny z SQL Server 2017, a więc bez Scalar Function Inlining):

Do wykonania mamy zapytanie, które wywołuje kilka i złączeń i funkcji okna:

Plan wykonania (a raczej jego część) wygląda następująco:

Nie wgłębiając się w poszczególne elementy samego planu możemy zauważyć, że poszczególne operatory są wykonywane na wielu wątkach. Powiedzmy, że chcemy usunąć spacje znajdujące się zarówno z przodu jak i z tyłu w zadanym tekście (pomijamy całkowicie fakt, że od SQL Server 2017 istnieje funkcja TRIM):

Powyższa funkcja jest funkcją skalarną czyli zwracającą pojedynczy wynik. Nasze zapytanie wraz z nią wygląda następująco:

Plan wykonania nieco różni się od tego, który przedstawiłem w poprzednim przypadku:

Co się stało z wielowątkowością? A no właśnie, cały plan stał się seryjny właśnie przez użycie stworzonej funkcji skalarnej.

Spróbujmy teraz zobaczyć jak wygląda sytuacja w SQL Server 2019 czyli zmieniamy Compatibility Level na 150:

Po uruchomieniu naszego zapytania i podejrzeniu planu możemy dostrzec na nim następujące operatory:

Mimo wywołania skalarnej funkcji użytkownika plan wykonywany jest na wielu wątkach o czym świadczy występowanie operatora Parallelism oraz graficzny znak z dwoma strzałkami wskazujący na wielowątkowość każdego ze wskazanych operatorów. Dodatkowo we właściwościach możemy dostrzec nową właściwość tj. Contains Inline Scalar Tsql Udfs ustawioną na TRUE:

Co się tak naprawdę stało i jak działa Scalar Function Inlining? W skrócie chodzi o to, że funkcja jest jest niejako interpretowana przez SQL i jej kod jest wywoływany tak jakby znajdował się w naszym zapytaniu zamiast ciągłego wywoływania zapisanej funkcji. Fakt ten możemy dostrzec w kodzie XML planu zapytania – tak to wygląda w starym podejściu:

W zapytaniu z SQL Server 2019 widzimy wywołanie “ciała” stworzonej przez nas funkcji skalarnej:

Naprawdę wygląda to całkiem nieźle. Pod kątem porównania kosztowego widzimy znaczącą różnicę:

Przy większych zapytaniach również powinniśmy dostrzec różnicę wydajnościową. Oczywiście nie wszystkie funkcje będą mogły być przepisane w ramach mechanizmu Scalar Function Inlining, sprawdzimy to za pomoca widoku sys.sql_modules:

Ten systemowy widok zwraca nam nasze funkcje oraz Atrybut is_inlineable wskazującą na to, czy stworzona przez nas funkcja w ogóle może być przepisana. Inline_type wskazuje czy opisywana funkcjonalność jest włączona (1) lub nie (0). Tutaj pojawia się pytanie kiedy funkcja nie będzie mogła być przepisana? Pełną listę wymogów znajdziecie tutaj – oto wybrane z nich:

  • funkcja nie używa funkcji niedeterministycznych opartych o czas jak GETDATE()
  • funkcja używa domyślnego ustawienia EXECUTE AS CALLER,
  • funkcja nie odwołuje się do zmiennych tabelarycznych lub parametrów tabelarycznych,
  • funkcja użytkownika nie jest używana w sekcji ORDER BY.
  • funkcja nie jest funkcją partycjonującą.

Pełną listę obostrzeń i ogólny opis znajdziecie oczywiście w dokumentacji (klik). Na ten moment oceniam opisywany mechanizm jako coś naprawdę wartego uwagi. Może on pomóc w wielu przypadkach bo z doświadczenia wiem, że funkcje użytkownika (w tym również te skalarne) są lubianą i popularną strukturą. Scalar Function Inlinging daje nam nadzieję na to, że niektóre problemy z nimi związane powoli odchodzą do lamusa.Pozdrawiam!

Leave a Comment

Your email address will not be published. Required fields are marked *