Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy:✅ końcowego punktu analizy SQL i magazynu danych w usłudze Microsoft Fabric
Microsoft Fabric Data Warehouse wykorzystuje dwie techniki inlining do uruchamiania skalarnych funkcji definiowanych przez użytkownika (UDF) jako części rozproszonych zapytań:
- Funkcja ExprBlock inlining obsługuje skalarne funkcje UDF bazujące wyłącznie na obliczeniach, które nie odwołują się do danych w treści funkcji, a także szeroką gamę form zapytań wywołujących.
- Wbudowywanie skalarnych funkcji UDF w usłudze Fabric Data Warehouse (wersja zapoznawcza) ma ścisłe wymagania zarówno dotyczące definicji funkcji, jak i wywołującego ją zapytania. Więcej informacji o obu technikach i ich wymaganiach można znaleźć w CREATE FUNCTION.
Note
Skalarne funkcje UDF są obecnie funkcją w wersji zapoznawczej w Fabric Data Warehouse.
W tym artykule dowiesz się, jak przekształcić UDF nieliniowalny w funkcję inlineowalną lub stworzyć UDF nieinlineowalny.
Zrób nieliniowalny skalarny UDF inlineowalny
Zmiany w kodzie T-SQL potrzebne, aby skalarny UDF był inlineowalny, zależą od tego, która konstrukcja uczyni jego definicję nieliniowalną.
Poniższe przykłady pokazują, jak przekształcić wiele instrukcji RETURN, @@ROWCOUNT oraz funkcję zależną od czasu w funkcji UDF służącej do dostępu do danych.
Zamień wiele wyciągów RETURN
Następująca funkcja odczytuje typ klienta z tabeli i zawiera wiele RETURN instrukcji. Ponieważ funkcja uzyskuje dostęp do danych tabelowych, obowiązują skalarne wymagania dotyczące inlining UDF. Wiele RETURN instrukcji sprawia, że tej definicji nie można zainlinować.
Określ WITH INLINE = AUTO, aby utworzyć funkcję, gdy przygotowujesz się do jej przepisania:
CREATE OR ALTER FUNCTION dbo.GetDiscount (@CustomerID INT)
RETURNS DECIMAL(5, 2)
WITH INLINE = AUTO
AS
BEGIN
DECLARE @CustomerType VARCHAR(20);
SELECT @CustomerType = CustomerType
FROM dbo.Customer
WHERE CustomerID = @CustomerID;
IF @CustomerType = 'Regular' RETURN 0.05;
IF @CustomerType = 'Premium' RETURN 0.10;
IF @CustomerType = 'VIP' RETURN 0.15;
RETURN 0.01;
END;
GO
Sprawdź, czy funkcja jest inlineowalna
Widok katalogowy sys.sql_modules ujawnia dwie właściwości opisujące skalarną liniowalność UDF:
-
is_inlineablewskazuje, czy definicja funkcji jest liniowa. Wartość1oznacza możliwą do wstawienia inline, a0oznacza niemożliwą do wstawienia inline. -
inline_eligibility_maskIdentyfikuje, która technika inlining może przetwarzać definicję funkcji. Więcej informacji o wartościach można znaleźć w sekcji Sprawdź, czy skalarny UDF można włożyć (inline).
Użyj następującego zapytania, aby sprawdzić dbo.GetDiscount:
SELECT
SCHEMA_NAME(o.schema_id) AS function_schema,
o.name AS function_name,
m.is_inlineable,
m.inline_eligibility_mask
FROM sys.sql_modules AS m
INNER JOIN sys.objects AS o
ON m.object_id = o.object_id
WHERE o.type = 'FN'
AND SCHEMA_NAME(o.schema_id) = 'dbo'
AND o.name = 'GetDiscount';
GO
Metadane opisują definicję funkcji. W przypadku początkowej definicji dbo.GetDiscount, is_inlineable ma wartość 0.
Przepisz funkcję, aby przypisać wynik zmiennej lokalnej i użyj jednego RETURN ostatecznego polecenia:
CREATE OR ALTER FUNCTION dbo.GetDiscount (@CustomerID INT)
RETURNS DECIMAL(5, 2)
AS
BEGIN
DECLARE @Discount DECIMAL(5, 2) = 0.01;
SELECT @Discount =
CASE CustomerType
WHEN 'Regular' THEN 0.05
WHEN 'Premium' THEN 0.10
WHEN 'VIP' THEN 0.15
ELSE 0.01
END
FROM dbo.Customer
WHERE CustomerID = @CustomerID;
RETURN @Discount;
END;
GO
Zrewidowana funkcja ma jedną instrukcję RETURN i spełnia wymagania dotyczące wbudowywania skalarnej funkcji UDF. Ponownie uruchom zapytanie metadanych, aby potwierdzić, że is_inlineable jest .1
Note
Inlining w ExprBlock obsługuje wiele RETURN instrukcji. Ten przykład odczytuje dane tabelowe i dlatego wykorzystuje skalarne inlinowanie UDF, które wymaga pojedynczego RETURN polecenia.
Zastąp @@ROWCOUNT wartością początkową
Następująca funkcja UDF dostępu do danych używa elementu @@ROWCOUNT, aby określić, czy jej zapytanie znalazło klienta.
@@ROWCOUNT nie jest obsługiwany przez wbudowywanie skalarnej funkcji UDF, więc definicja nie może być wbudowana:
CREATE OR ALTER FUNCTION dbo.CustomerExists (@CustomerID INT)
RETURNS BIT
WITH INLINE = AUTO
AS
BEGIN
DECLARE @CustomerExists BIT = 1;
SELECT @CustomerExists = 1
FROM dbo.Customer
WHERE CustomerID = @CustomerID;
IF @@ROWCOUNT = 0 SET @CustomerExists = 0;
RETURN @CustomerExists;
END;
GO
Zainicjalizuj zmienną wartością wyniku dla przypadku braku pasującego wiersza. Element SELECT zmienia wartość tylko wtedy, gdy zostanie znaleziony wiersz, co eliminuje potrzebę sprawdzania @@ROWCOUNT:
CREATE OR ALTER FUNCTION dbo.CustomerExists (@CustomerID INT)
RETURNS BIT
AS
BEGIN
DECLARE @CustomerExists BIT = 0;
SELECT @CustomerExists = 1
FROM dbo.Customer
WHERE CustomerID = @CustomerID;
RETURN @CustomerExists;
END;
GO
Uruchom zapytanie metadanych z poprzedniego przykładu z CustomerExists nazwą funkcji. Początkowa definicja ma is_inlineable = 0, a zmieniona definicja ma .is_inlineable = 1
Przekaż wartość zależną od czasu do funkcji UDF uzyskującej dostęp do danych
Następująca funkcja łączy dostęp do tabeli z .GETUTCDATE() Dostęp do tabel wymaga skalarnego inliningu UDF, gdzie funkcja zależna od czasu w ciele UDF sprawia, że definicja nie jest inlineowalna:
CREATE OR ALTER FUNCTION dbo.GetCustomerTenureDays (@CustomerID INT)
RETURNS INT
WITH INLINE = AUTO
AS
BEGIN
DECLARE @MemberSince DATE;
SELECT @MemberSince = MemberSince
FROM dbo.Customer
WHERE CustomerID = @CustomerID;
RETURN DATEDIFF(DAY, @MemberSince, GETUTCDATE());
END;
GO
Zamiast tego przekaż aktualną datę i godzinę do funkcji jako parametr:
CREATE OR ALTER FUNCTION dbo.GetCustomerTenureDays
(
@CustomerID INT,
@AsOfDate DATETIME2(6)
)
RETURNS INT
AS
BEGIN
DECLARE @MemberSince DATE;
SELECT @MemberSince = MemberSince
FROM dbo.Customer
WHERE CustomerID = @CustomerID;
RETURN DATEDIFF(DAY, @MemberSince, @AsOfDate);
END;
GO
Oblicz GETUTCDATE() w zapytaniu wywołującym i przekaż jego wartość do funkcji UDF:
SELECT
CustomerID,
CustomerName,
dbo.GetCustomerTenureDays(CustomerID, GETUTCDATE()) AS TenureDays
FROM dbo.Customer
ORDER BY CustomerID;
GO
Zrób zapytanie inlineowalne
Wymagania dotyczące kształtu zapytania w tej sekcji mają zastosowanie, gdy przynajmniej jeden UDF w zapytaniu opiera się na skalarnym inliningu UDF. Gdy każdy UDF w zapytaniu jest obsługiwany przez inlining w ExprBlock, te kształty zapytań działają bez powtórzeń pokazanych tutaj.
Poniższe przykłady wykorzystują wersję z dostępem do danych z dbo.GetDiscount poprzedniej sekcji.
Zastąp wspólne wyrażenie tabelaryczne
Zapytanie używające wspólnego wyrażenia tabelowego (CTE) nie może inlineować funkcji zależnej od skalarnego inliningu UDF. Następujące zapytanie nie jest obsługiwane:
WITH CustomerDiscounts AS
(
SELECT
CustomerID,
CustomerName,
dbo.GetDiscount(CustomerID) AS DiscountRate
FROM dbo.Customer
)
SELECT CustomerID, CustomerName, DiscountRate
FROM CustomerDiscounts;
GO
Materializuj wynik w tabeli tymczasowej, a następnie zapytaj tabelę tymczasową:
DROP TABLE IF EXISTS #CustomerDiscounts;
GO
CREATE TABLE #CustomerDiscounts
(
CustomerID INT NOT NULL,
CustomerName VARCHAR(100) NOT NULL,
DiscountRate DECIMAL(5, 2) NOT NULL
)
WITH (DISTRIBUTION = ROUND_ROBIN);
GO
INSERT INTO #CustomerDiscounts
(
CustomerID,
CustomerName,
DiscountRate
)
SELECT
CustomerID,
CustomerName,
dbo.GetDiscount(CustomerID)
FROM dbo.Customer;
GO
SELECT CustomerID, CustomerName, DiscountRate
FROM #CustomerDiscounts;
GO
Przenieś wywołanie UDF poza GRUPĘ BY
Następujące zapytanie wywołuje UDF bezpośrednio w klauzuli GROUP BY i nie jest obsługiwane dla funkcji zależnej od skalarnego inliningu UDF:
SELECT
dbo.GetDiscount(CustomerID) AS DiscountRate,
COUNT(*) AS CustomerCount
FROM dbo.Customer
GROUP BY dbo.GetDiscount(CustomerID);
GO
Oblicz wynik UDF w tabeli pochodnej, a następnie grupuj wynik w zewnętrznym zapytaniu:
SELECT
DiscountRate,
COUNT(*) AS CustomerCount
FROM
(
SELECT dbo.GetDiscount(CustomerID) AS DiscountRate
FROM dbo.Customer
) AS CustomerDiscounts
GROUP BY DiscountRate;
GO
Użyj aliasu kolumny w klauzuli ORDER BY
Unikaj bezpośredniego wywoływania w klauzuli ORDER BY funkcji UDF zależnej od wbudowywania skalarnej funkcji UDF. Wyświetl wynik tylko raz i posortuj według aliasu kolumny lub jej numeru porządkowego:
SELECT
CustomerID,
CustomerName,
dbo.GetDiscount(CustomerID) AS DiscountRate
FROM dbo.Customer
ORDER BY DiscountRate;
GO
Utwórz skalarną funkcję UDF niepodlegającą inline'owaniu
Możesz potrzebować funkcji do samodzielnego obliczenia, nawet jeśli jej definicja nie może być włożona. Na przykład aplikacja lub raport może raz wywołać UDF, aby obliczyć metrykę biznesową.
Następująca funkcja odczytuje przychody od początku roku z tabeli klientów, a następnie używa pętli WHILE do dodawania średnich miesięcznych przychodów za każdy pozostały miesiąc. Ponieważ funkcja uzyskuje dostęp do danych tabelowych, opiera się na skalarnym inliningu UDF, który nie obsługuje WHILE. Definicja funkcji jest zatem nieliniowana.
Użyj WITH INLINE = AUTO do umożliwienia utworzenia funkcji, mimo że jej definicja nie jest inlineowalna:
CREATE OR ALTER FUNCTION dbo.GetProjectedAnnualRevenue (@MonthsElapsed INT)
RETURNS DECIMAL(18, 2)
WITH INLINE = AUTO
AS
BEGIN
DECLARE @YearToDateRevenue DECIMAL(38, 6);
DECLARE @ProjectedRevenue DECIMAL(38, 6);
DECLARE @MonthNumber INT = @MonthsElapsed + 1;
IF @MonthsElapsed BETWEEN 1 AND 12
BEGIN
SELECT @YearToDateRevenue = SUM(YearToDateRevenue)
FROM dbo.Customer;
SET @ProjectedRevenue = @YearToDateRevenue;
WHILE @MonthNumber <= 12
BEGIN
SET @ProjectedRevenue =
@ProjectedRevenue + (@YearToDateRevenue / @MonthsElapsed);
SET @MonthNumber = @MonthNumber + 1;
END;
END;
RETURN @ProjectedRevenue;
END;
GO
Użyj osobnego połączenia, aby raz obliczyć metrykę dla dashboardu:
DECLARE @ProjectedAnnualRevenue DECIMAL(18, 2);
SET @ProjectedAnnualRevenue =
dbo.GetProjectedAnnualRevenue(MONTH(GETUTCDATE()));
SELECT @ProjectedAnnualRevenue AS ProjectedAnnualRevenue;
GO
Zapytanie zwraca prognozowany roczny przychód na podstawie średniego miesięcznego przychodu do końca bieżącego miesiąca UTC.
INLINE = AUTO pozwala na utworzenie tej funkcji, ale nie czyni funkcji nieinlineowalnej do użycia w rozproszonym zapytaniu. Na przykład nie można użyć dbo.GetProjectedAnnualRevenue w zapytaniu SELECT ... FROM dbo.Customer.