Files
sql-server-samples/samples/features/intelligent-query-processing/notebooks/Scalar_UDF_Inlining.ipynb
T
2019-11-03 16:09:56 -08:00

93 KiB

Scalar UDF Inlining

User-Defined Functions that are implemented in Transact-SQL and return a single data value are referred to as T-SQL Scalar User-Defined Functions. T-SQL UDFs are an elegant way to achieve code reuse and modularity across SQL queries. Some computations (such as complex business rules) are easier to express in imperative UDF form. UDFs help in building up complex logic without requiring expertise in writing complex SQL queries. Scalar UDF inlining, a feature the Intelligent Query Processing suite of features. This feature improves the performance of queries that invoke scalar UDFs in SQL Server (starting with SQL Server 2019).

This example will show you how upgrading to Database Compatibility Level 150 could improve performance of queries which leverage scalar UDFs. More information about this feature is available here.

Step 1: Setup WideWorldImportersDW database

You could choose to use a container to evaluate this feature. Create an instance of SQL Server 2019 using a Docker image and restore the WideWorldImportersDW database backup

You will need the WideWorldImportersDW database for this exercise. If you don't have this sample database, then you download the sample database here.

Restore the copied WideWorldImportersDW database backup into the container and restore the backup.

Docker Commands
docker pull mcr.microsoft.com/mssql/server:2019-latest

docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=`<A Strong Password`>" -p 1445:1433 --name sql2019demo -d mcr.microsoft.com/mssql/server:2019-latest

docker cp ".\Downloads\WideWorldImportersDW-Full.bak" sql2019demo:/var/opt/mssql/data

Note: For Linux installations the default path to use is /var/opt/mssql

In [7]:
USE [master]
GO
IF EXISTS (SELECT [database_id] FROM sys.databases WHERE [name] = 'WideWorldImportersDW')
ALTER DATABASE [WideWorldImportersDW] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

DECLARE @datafilepath VARCHAR(8000) = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS VARCHAR(4000)) + 'WideWorldImportersDW.mdf'
DECLARE @logfilepath VARCHAR(8000) = CAST(SERVERPROPERTY('InstanceDefaultLogPath') AS VARCHAR(4000)) + 'WideWorldImportersDW.ldf'
DECLARE @inmemfilepath VARCHAR(8000) = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS VARCHAR(4000)) + 'WideWorldImportersDW_InMemory_Data_1'
DECLARE @secondaryfilepath VARCHAR(8000) = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS VARCHAR(4000))+ 'WideWorldImportersDW_2.ndf'

-- Change @backupfile file path as needed
DECLARE @backupfile VARCHAR(8000) = 'E:\SampleDBs\WideWorldImportersDW-Full.bak'
RESTORE DATABASE WideWorldImportersDW
FROM DISK = @backupfile 
WITH MOVE 'WWI_Primary' TO @datafilepath,
    MOVE 'WWI_UserData' TO @secondaryfilepath,
    MOVE 'WWIDW_InMemory_Data_1' TO @inmemfilepath,
    MOVE 'WWI_Log' TO @logfilepath, NOUNLOAD, REPLACE, STATS = 10
GO

USE [master]
GO
ALTER DATABASE [WideWorldImportersDW] MODIFY FILE ( NAME = N'WWI_Log', SIZE = 4GB )
GO

Step 2: Enlarge the WideWorldImportersDW database

In [3]:
USE WideWorldImportersDW;
GO

/*
Assumes a fresh restore of WideWorldImportersDW
*/

IF OBJECT_ID('Fact.OrderHistory') IS NULL 
BEGIN
    SELECT [Order Key], [City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], Description, Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], [Total Including Tax], [Lineage Key]
    INTO Fact.OrderHistory
    FROM Fact.[Order];
END;

ALTER TABLE Fact.OrderHistory
ADD CONSTRAINT PK_Fact_OrderHistory PRIMARY KEY NONCLUSTERED ([Order Key] ASC, [Order Date Key] ASC) WITH (DATA_COMPRESSION = PAGE);
GO

CREATE INDEX IX_Stock_Item_Key
ON Fact.OrderHistory ([Stock Item Key])
INCLUDE(Quantity)
WITH (DATA_COMPRESSION = PAGE);
GO

CREATE INDEX IX_OrderHistory_Quantity
ON Fact.OrderHistory ([Quantity])
INCLUDE([Order Key])
WITH (DATA_COMPRESSION = PAGE);
GO

CREATE INDEX IX_OrderHistory_CustomerKey
ON Fact.OrderHistory([Customer Key])
INCLUDE ([Total Including Tax])
WITH (DATA_COMPRESSION = PAGE);
GO

IF (SELECT COUNT(*) FROM [Fact].[OrderHistory]) < 3702592
BEGIN
	DECLARE @i smallint
	SET @i = 0
	WHILE @i < 4
	BEGIN
		INSERT INTO [Fact].[OrderHistory] ([City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], Description, Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], [Total Including Tax], [Lineage Key])
		SELECT [City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], Description, Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], [Total Including Tax], [Lineage Key]
		FROM [Fact].[OrderHistory];

		SET @i = @i +1
	END;
END
GO

IF OBJECT_ID('Fact.OrderHistoryExtended') IS NULL 
BEGIN
    SELECT [Order Key], [City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], Description, Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], [Total Including Tax], [Lineage Key]
    INTO Fact.OrderHistoryExtended
    FROM Fact.[OrderHistory];
END;

ALTER TABLE Fact.OrderHistoryExtended
ADD CONSTRAINT PK_Fact_OrderHistoryExtended PRIMARY KEY NONCLUSTERED ([Order Key] ASC, [Order Date Key] ASC)
WITH (DATA_COMPRESSION = PAGE);
GO

CREATE INDEX IX_Stock_Item_Key
ON Fact.OrderHistoryExtended ([Stock Item Key])
INCLUDE (Quantity);
GO

IF (SELECT COUNT(*) FROM [Fact].[OrderHistory]) < 29620736
BEGIN
	DECLARE @i smallint
	SET @i = 0
	WHILE @i < 3
	BEGIN
		INSERT Fact.OrderHistoryExtended([City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], Description, Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], [Total Including Tax], [Lineage Key])
		SELECT [City Key], [Customer Key], [Stock Item Key], [Order Date Key], [Picked Date Key], [Salesperson Key], [Picker Key], [WWI Order ID], [WWI Backorder ID], Description, Package, Quantity, [Unit Price], [Tax Rate], [Total Excluding Tax], [Tax Amount], [Total Including Tax], [Lineage Key]
		FROM Fact.OrderHistoryExtended;

		SET @i = @i +1
	END;
END
GO

UPDATE Fact.OrderHistoryExtended
SET [WWI Order ID] = [Order Key];
GO

-- Repeat the following until log shrinks. These demos don't require much log space.
CHECKPOINT
GO
DBCC SHRINKFILE (N'WWI_Log' , 0, TRUNCATEONLY)
GO
SELECT * FROM sys.dm_db_log_space_usage
GO

Step 3: Create a T-SQL Scalar UDF

In [4]:
USE [WideWorldImportersDW];
GO

CREATE OR ALTER FUNCTION dbo.ufn_customer_category(@CustomerKey INT) 
RETURNS CHAR(10) AS
BEGIN
    DECLARE @total_amount DECIMAL(18,2);
    DECLARE @category CHAR(10);

    SELECT @total_amount = 
    SUM([Total Including Tax]) 
    FROM [Fact].[OrderHistory]
    WHERE [Customer Key] = @CustomerKey;

    IF @total_amount < 500000
    SET @category = 'REGULAR';
    ELSE IF @total_amount < 1000000
    SET @category = 'GOLD';
    ELSE 
    SET @category = 'PLATINUM';

    RETURN @category;
END
GO
Commands completed successfully.
Commands completed successfully.
Total execution time: 00:00:00.027

Step 4: Finding if your T-SQL UDFs is inlineable

In the result set, scroll to the left and notice the value of the is_inlineable column. The value 1 shows that the UDF has inlineable constructs, meaning imperative statements that can be expressed in relational expressions. For example, an IF <expression> ELSE statement can be expressed as an inline SELECT CASE WHEN <expression> THE 1 ELSE 0 END AS <column> statement, or a SET @var = <expression> can be inlined as SELECT <expression> AS var.

The relational expressions for imperative statements handled by the Scalar UDF Inlining feature can be found in the “Froid: Optimization of Imperative Programs in a Relational Database” paper by Microsoft’s Gray Systems Lab in Madison Wisconsin.

In [5]:
USE [WideWorldImportersDW];
GO
SELECT * FROM sys.sql_modules
WHERE object_id = OBJECT_ID('ufn_customer_category')
GO
Out [5]:
Commands completed successfully.
(1 row affected)
Total execution time: 00:00:00.043
object_iddefinitionuses_ansi_nullsuses_quoted_identifieris_schema_bounduses_database_collationis_recompilednull_on_null_inputexecute_as_principal_iduses_native_compilationinline_typeis_inlineable
1954106002 CREATE FUNCTION dbo.ufn_customer_category(@CustomerKey INT) RETURNS CHAR(10) AS BEGIN DECLARE @total_amount DECIMAL(18,2); DECLARE @category CHAR(10); SELECT @total_amount = SUM([Total Including Tax]) FROM [Fact].[OrderHistory] WHERE [Customer Key] = @CustomerKey; IF @total_amount < 500000 SET @category = 'REGULAR'; ELSE IF @total_amount < 1000000 SET @category = 'GOLD'; ELSE SET @category = 'PLATINUM'; RETURN @category; END 110000NULL011

Step 5: Execute the query without Scalar UDF Inlining

Even when the database compatibility level is set to the defauult (150), this can be done by using the USE HINT DISABLE_TSQL_SCALAR_UDF_INLINING query hint to disable the feature.

In [3]:
USE [WideWorldImportersDW];
GO
ALTER DATABASE [WideWorldImportersDW] SET COMPATIBILITY_LEVEL = 150;
GO
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
GO

SELECT TOP 100 [Customer Key], [Customer],
       dbo.ufn_customer_category([Customer Key]) AS [Discount Price]
FROM [Dimension].[Customer]
ORDER BY [Customer Key]
OPTION (RECOMPILE,USE HINT('DISABLE_TSQL_SCALAR_UDF_INLINING'));
GO
Out [3]:
Commands completed successfully.
Commands completed successfully.
Commands completed successfully.
(100 rows affected)
Total execution time: 00:00:09.630
Customer KeyCustomerDiscount Price
0UnknownPLATINUM
1Tailspin Toys (Head Office)PLATINUM
2Tailspin Toys (Sylvanite, MT)PLATINUM
3Tailspin Toys (Peeples Valley, AZ)PLATINUM
4Tailspin Toys (Medicine Lodge, KS)PLATINUM
5Tailspin Toys (Gasport, NY)PLATINUM
6Tailspin Toys (Jessie, ND)PLATINUM
7Tailspin Toys (Frankewing, TN)PLATINUM
8Tailspin Toys (Bow Mar, CO)PLATINUM
9Tailspin Toys (Netcong, NJ)PLATINUM
10Tailspin Toys (Wimbledon, ND)PLATINUM
11Tailspin Toys (Devault, PA)PLATINUM
12Tailspin Toys (Biscay, MN)PLATINUM
13Tailspin Toys (Stonefort, IL)PLATINUM
14Tailspin Toys (Long Meadow, MD)PLATINUM
15Tailspin Toys (Batson, TX)PLATINUM
16Tailspin Toys (Coney Island, MO)PLATINUM
17Tailspin Toys (East Fultonham, OH)PLATINUM
18Tailspin Toys (Goffstown, NH)PLATINUM
19Tailspin Toys (Lemeta, AK)PLATINUM
20Tailspin Toys (College Place, WA)PLATINUM
21Tailspin Toys (Tresckow, PA)PLATINUM
22Tailspin Toys (Ward Ridge, FL)PLATINUM
23Tailspin Toys (Ikatan, AK)PLATINUM
24Tailspin Toys (Dundarrach, NC)PLATINUM
25Tailspin Toys (Avenal, CA)PLATINUM
26Tailspin Toys (Hedrick, IA)PLATINUM
27Tailspin Toys (Bowlus, MN)PLATINUM
28Tailspin Toys (North Ridge, NY)PLATINUM
29Tailspin Toys (Eulaton, AL)PLATINUM
30Tailspin Toys (Koontzville, WA)PLATINUM
31Tailspin Toys (Lake Stevens, WA)PLATINUM
32Tailspin Toys (Maypearl, TX)PLATINUM
33Tailspin Toys (Boyden Arbor, SC)PLATINUM
34Tailspin Toys (Dallardsville, TX)PLATINUM
35Tailspin Toys (Slanesville, WV)PLATINUM
36Tailspin Toys (Ekron, KY)PLATINUM
37Tailspin Toys (Kerby, OR)PLATINUM
38Tailspin Toys (Airport Drive, MO)PLATINUM
39Tailspin Toys (Diablock, KY)PLATINUM
40Tailspin Toys (Impact, TX)PLATINUM
41Tailspin Toys (Olivette, MO)PLATINUM
42Tailspin Toys (Arietta, NY)PLATINUM
43Tailspin Toys (Upper Preston, WA)PLATINUM
44Tailspin Toys (Amanda Park, WA)PLATINUM
45Tailspin Toys (Severna Park, MD)PLATINUM
46Tailspin Toys (Jemison, AL)PLATINUM
47Tailspin Toys (Lake Hughes, CA)PLATINUM
48Tailspin Toys (Trentwood, WA)PLATINUM
49Tailspin Toys (Muir, MI)PLATINUM
50Tailspin Toys (Hambleton, WV)PLATINUM
51Tailspin Toys (Imlaystown, NJ)PLATINUM
52Tailspin Toys (Idria, CA)PLATINUM
53Tailspin Toys (Nanafalia, AL)PLATINUM
54Tailspin Toys (Railroad, PA)PLATINUM
55Tailspin Toys (Gum Branch, GA)PLATINUM
56Tailspin Toys (Royal City, WA)PLATINUM
57Tailspin Toys (Lakemore, OH)PLATINUM
58Tailspin Toys (Mappsburg, VA)PLATINUM
59Tailspin Toys (Edgartown, MA)PLATINUM
60Tailspin Toys (East Dailey, WV)PLATINUM
61Tailspin Toys (Fairfield Glade, TN)PLATINUM
62Tailspin Toys (Great Neck Estates, NY)PLATINUM
63Tailspin Toys (Stallion Springs, CA)PLATINUM
64Tailspin Toys (Hodgdon, ME)PLATINUM
65Tailspin Toys (North Cowden, TX)PLATINUM
66Tailspin Toys (Madaket, MA)PLATINUM
67Tailspin Toys (Sentinel Butte, ND)PLATINUM
68Tailspin Toys (Gardere, LA)PLATINUM
69Tailspin Toys (Lytle Creek, CA)PLATINUM
70Tailspin Toys (New Baden, IL)PLATINUM
71Tailspin Toys (Good Hart, MI)PLATINUM
72Tailspin Toys (Cortaro, AZ)PLATINUM
73Tailspin Toys (Cokato, MN)PLATINUM
74Tailspin Toys (Indios, PR)PLATINUM
75Tailspin Toys (Windsor Locks, CT)PLATINUM
76Tailspin Toys (Yewed, OK)PLATINUM
77Tailspin Toys (Hahira, GA)PLATINUM
78Tailspin Toys (Sekiu, WA)PLATINUM
79Tailspin Toys (Page City, KS)PLATINUM
80Tailspin Toys (Valdese, NC)PLATINUM
81Tailspin Toys (Big Moose, NY)PLATINUM
82Tailspin Toys (La Cueva, NM)PLATINUM
83Tailspin Toys (Absecon, NJ)PLATINUM
84Tailspin Toys (Aceitunas, PR)PLATINUM
85Tailspin Toys (Andrix, CO)PLATINUM
86Tailspin Toys (New Lexington, OH)PLATINUM
87Tailspin Toys (Sauquoit, NY)PLATINUM
88Tailspin Toys (Dracut, MA)PLATINUM
89Tailspin Toys (Victory Gardens, NJ)PLATINUM
90Tailspin Toys (Tolna, ND)PLATINUM
91Tailspin Toys (Alstead, NH)PLATINUM
92Tailspin Toys (Sans Souci, SC)PLATINUM
93Tailspin Toys (Clewiston, FL)PLATINUM
94Tailspin Toys (Cheyenne Wells, CO)PLATINUM
95Tailspin Toys (Lavon, TX)PLATINUM
96Tailspin Toys (South La Paloma, TX)PLATINUM
97Tailspin Toys (Manchester Center, VT)PLATINUM
98Tailspin Toys (El Centro, CA)PLATINUM
99Tailspin Toys (Guin, AL)PLATINUM

Observe the query execution plan (or actual plan).

ScalarUDF_Disabled_Plan

Notice the simplicity of the plan and estimated cost percentage for each operator. There is no cost estimated for the Compute Scalar because these are not realistically costed.

The iterative invocation nature of the UDF is also obfuscated from the plan:

  • Possibly complex logic that may be inside the UDF is not surfaced to the plan.
  • The time spent in a scalar UDF invocation is also not surfaced in the Compute Scalar. As seen in the QueryTimeStats property of the SELECT, the UDF was responsible for the bulk of the elasped and CPU time in this query's execution, and at first glance that CPU cost is not identifiable in the plan.

ScalarUDF_Disabled_Properties

Also note that the plan was executed serially. Scalar UDFs are parallelism inhibitors.

Step 4: Execute the query by removing any hint restriction

Run the same query from Step 3, but now without any hint, allowing SQL Server to operate as default.

In [5]:
USE [WideWorldImportersDW];
GO
ALTER DATABASE [WideWorldImportersDW] SET COMPATIBILITY_LEVEL = 150;
GO
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
GO

SELECT TOP 100 [Customer Key], [Customer],
       dbo.ufn_customer_category([Customer Key]) AS [Discount Price]
FROM [Dimension].[Customer]
ORDER BY [Customer Key]
OPTION (RECOMPILE);
GO
Out [5]:
Commands completed successfully.
Commands completed successfully.
Commands completed successfully.
(100 rows affected)
Total execution time: 00:00:01.089
Customer KeyCustomerDiscount Price
0UnknownPLATINUM
1Tailspin Toys (Head Office)PLATINUM
2Tailspin Toys (Sylvanite, MT)PLATINUM
3Tailspin Toys (Peeples Valley, AZ)PLATINUM
4Tailspin Toys (Medicine Lodge, KS)PLATINUM
5Tailspin Toys (Gasport, NY)PLATINUM
6Tailspin Toys (Jessie, ND)PLATINUM
7Tailspin Toys (Frankewing, TN)PLATINUM
8Tailspin Toys (Bow Mar, CO)PLATINUM
9Tailspin Toys (Netcong, NJ)PLATINUM
10Tailspin Toys (Wimbledon, ND)PLATINUM
11Tailspin Toys (Devault, PA)PLATINUM
12Tailspin Toys (Biscay, MN)PLATINUM
13Tailspin Toys (Stonefort, IL)PLATINUM
14Tailspin Toys (Long Meadow, MD)PLATINUM
15Tailspin Toys (Batson, TX)PLATINUM
16Tailspin Toys (Coney Island, MO)PLATINUM
17Tailspin Toys (East Fultonham, OH)PLATINUM
18Tailspin Toys (Goffstown, NH)PLATINUM
19Tailspin Toys (Lemeta, AK)PLATINUM
20Tailspin Toys (College Place, WA)PLATINUM
21Tailspin Toys (Tresckow, PA)PLATINUM
22Tailspin Toys (Ward Ridge, FL)PLATINUM
23Tailspin Toys (Ikatan, AK)PLATINUM
24Tailspin Toys (Dundarrach, NC)PLATINUM
25Tailspin Toys (Avenal, CA)PLATINUM
26Tailspin Toys (Hedrick, IA)PLATINUM
27Tailspin Toys (Bowlus, MN)PLATINUM
28Tailspin Toys (North Ridge, NY)PLATINUM
29Tailspin Toys (Eulaton, AL)PLATINUM
30Tailspin Toys (Koontzville, WA)PLATINUM
31Tailspin Toys (Lake Stevens, WA)PLATINUM
32Tailspin Toys (Maypearl, TX)PLATINUM
33Tailspin Toys (Boyden Arbor, SC)PLATINUM
34Tailspin Toys (Dallardsville, TX)PLATINUM
35Tailspin Toys (Slanesville, WV)PLATINUM
36Tailspin Toys (Ekron, KY)PLATINUM
37Tailspin Toys (Kerby, OR)PLATINUM
38Tailspin Toys (Airport Drive, MO)PLATINUM
39Tailspin Toys (Diablock, KY)PLATINUM
40Tailspin Toys (Impact, TX)PLATINUM
41Tailspin Toys (Olivette, MO)PLATINUM
42Tailspin Toys (Arietta, NY)PLATINUM
43Tailspin Toys (Upper Preston, WA)PLATINUM
44Tailspin Toys (Amanda Park, WA)PLATINUM
45Tailspin Toys (Severna Park, MD)PLATINUM
46Tailspin Toys (Jemison, AL)PLATINUM
47Tailspin Toys (Lake Hughes, CA)PLATINUM
48Tailspin Toys (Trentwood, WA)PLATINUM
49Tailspin Toys (Muir, MI)PLATINUM
50Tailspin Toys (Hambleton, WV)PLATINUM
51Tailspin Toys (Imlaystown, NJ)PLATINUM
52Tailspin Toys (Idria, CA)PLATINUM
53Tailspin Toys (Nanafalia, AL)PLATINUM
54Tailspin Toys (Railroad, PA)PLATINUM
55Tailspin Toys (Gum Branch, GA)PLATINUM
56Tailspin Toys (Royal City, WA)PLATINUM
57Tailspin Toys (Lakemore, OH)PLATINUM
58Tailspin Toys (Mappsburg, VA)PLATINUM
59Tailspin Toys (Edgartown, MA)PLATINUM
60Tailspin Toys (East Dailey, WV)PLATINUM
61Tailspin Toys (Fairfield Glade, TN)PLATINUM
62Tailspin Toys (Great Neck Estates, NY)PLATINUM
63Tailspin Toys (Stallion Springs, CA)PLATINUM
64Tailspin Toys (Hodgdon, ME)PLATINUM
65Tailspin Toys (North Cowden, TX)PLATINUM
66Tailspin Toys (Madaket, MA)PLATINUM
67Tailspin Toys (Sentinel Butte, ND)PLATINUM
68Tailspin Toys (Gardere, LA)PLATINUM
69Tailspin Toys (Lytle Creek, CA)PLATINUM
70Tailspin Toys (New Baden, IL)PLATINUM
71Tailspin Toys (Good Hart, MI)PLATINUM
72Tailspin Toys (Cortaro, AZ)PLATINUM
73Tailspin Toys (Cokato, MN)PLATINUM
74Tailspin Toys (Indios, PR)PLATINUM
75Tailspin Toys (Windsor Locks, CT)PLATINUM
76Tailspin Toys (Yewed, OK)PLATINUM
77Tailspin Toys (Hahira, GA)PLATINUM
78Tailspin Toys (Sekiu, WA)PLATINUM
79Tailspin Toys (Page City, KS)PLATINUM
80Tailspin Toys (Valdese, NC)PLATINUM
81Tailspin Toys (Big Moose, NY)PLATINUM
82Tailspin Toys (La Cueva, NM)PLATINUM
83Tailspin Toys (Absecon, NJ)PLATINUM
84Tailspin Toys (Aceitunas, PR)PLATINUM
85Tailspin Toys (Andrix, CO)PLATINUM
86Tailspin Toys (New Lexington, OH)PLATINUM
87Tailspin Toys (Sauquoit, NY)PLATINUM
88Tailspin Toys (Dracut, MA)PLATINUM
89Tailspin Toys (Victory Gardens, NJ)PLATINUM
90Tailspin Toys (Tolna, ND)PLATINUM
91Tailspin Toys (Alstead, NH)PLATINUM
92Tailspin Toys (Sans Souci, SC)PLATINUM
93Tailspin Toys (Clewiston, FL)PLATINUM
94Tailspin Toys (Cheyenne Wells, CO)PLATINUM
95Tailspin Toys (Lavon, TX)PLATINUM
96Tailspin Toys (South La Paloma, TX)PLATINUM
97Tailspin Toys (Manchester Center, VT)PLATINUM
98Tailspin Toys (El Centro, CA)PLATINUM
99Tailspin Toys (Guin, AL)PLATINUM

Observe the query execution plan (or actual plan). Notice the plan now inlines the UDF logic, and SQL Server was able to optimize the plan adequately. As you can see from the execution times, the query with Batch Mode for Rowstore finished much faster! From ~9s to ~1s.

ScalarUDF_Enabled_Plan

Notice the QueryTimeStats property of the SELECT:

  • The query elapsed and CPU time are identical, which means there is no hidden cost and that is immediately apparent when looking at the plan (for example in the TOP operator. Remember the operator time is cumulative up the plan tree in row mode execution).
  • There is no UDF-related execution statistic s, because the UDF was not executed. Instead, its logic was automatically inlined.

ScalarUDF_enabled_properties