Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

Commit 2cfa794

Browse files
committed
Edit pass
1 parent 42a3f65 commit 2cfa794

1 file changed

Lines changed: 33 additions & 26 deletions

File tree

docs/relational-databases/user-defined-functions/scalar-udf-inlining.md

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: The scalar UDF inlining feature improves performance of queries tha
44
author: s-r-k
55
ms.author: karam
66
ms.reviewer: randolphwest
7-
ms.date: 09/21/2024
7+
ms.date: 10/15/2024
88
ms.service: sql
99
ms.topic: conceptual
1010
monikerRange: "=azuresqldb-current || >=sql-server-ver15 || >=sql-server-linux-ver15"
@@ -35,7 +35,7 @@ Scalar UDFs typically end up performing poorly due to the following reasons:
3535

3636
The goal of the scalar UDF inlining feature is to improve performance of queries that invoke T-SQL scalar UDFs, where UDF execution is the main bottleneck.
3737

38-
With this new feature, scalar UDFs are automatically transformed into scalar expressions or scalar subqueries that are substituted in the calling query in place of the UDF operator. These expressions and subqueries are then optimized. As a result, the query plan no longer has a user-defined function operator, but its effects are observed in the plan, like views or inline TVFs.
38+
With this new feature, scalar UDFs are automatically transformed into scalar expressions or scalar subqueries that are substituted in the calling query in place of the UDF operator. These expressions and subqueries are then optimized. As a result, the query plan no longer has a user-defined function operator, but its effects are observed in the plan, like views or inline table-valued functions (TVFs).
3939

4040
## Examples
4141

@@ -137,7 +137,7 @@ For the same query, the plan with the UDF inlined looks as follows.
137137

138138
As mentioned earlier, the query plan no longer has a user-defined function operator, but its effects are now observable in the plan, like views or inline TVFs. Here are some key observations from the previous plan:
139139

140-
- [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] infers the implicit join between `CUSTOMER` and `ORDERS` and makes that explicit via a join operator.
140+
- [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] infers the implicit join between `CUSTOMER` and `ORDERS` and makes it explicit via a join operator.
141141

142142
- [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] also infers the implicit `GROUP BY O_CUSTKEY on ORDERS` and uses the IndexSpool + StreamAggregate to implement it.
143143

@@ -149,23 +149,23 @@ Depending upon the complexity of the logic in the UDF, the resulting query plan
149149

150150
## Inlineable scalar UDF requirements
151151

152-
A scalar T-SQL UDF can be inlined if the function definition uses allowed constructs AND the function is used in a context that enables inlining:
152+
A scalar T-SQL UDF can be inlined if the function definition uses allowed constructs, and the function is used in a context that enables inlining:
153153

154-
Requirements of the UDF definition of the UDF, all must be true
154+
All of the following conditions of the *UDF definition* must be true:
155155

156156
- The UDF is written using the following constructs:
157157
- `DECLARE`, `SET`: Variable declaration and assignments.
158158
- `SELECT`: SQL query with single/multiple variable assignments <sup>1</sup>.
159159
- `IF`/`ELSE`: Branching with arbitrary levels of nesting.
160160
- `RETURN`: Single or multiple return statements. Starting with [!INCLUDE [sql-server-2019](../../includes/sssql19-md.md)] CU5, the UDF can only contain a single RETURN statement to be considered for inlining <sup>6</sup>.
161161
- `UDF`: Nested/recursive function calls <sup>2</sup>.
162-
- Others: Relational operations such as `EXISTS`, `IS `NULL``.
162+
- Others: Relational operations such as `EXISTS`, `IS NULL`.
163163
- The UDF doesn't invoke any intrinsic function that is either time-dependent (such as `GETDATE()`) or has side effects <sup>3</sup> (such as `NEWSEQUENTIALID()`).
164164
- The UDF uses the `EXECUTE AS CALLER` clause (default behavior if the `EXECUTE AS` clause isn't specified).
165165
- The UDF doesn't reference table variables or table-valued parameters.
166166
- The UDF isn't natively compiled (interop is supported).
167167
- The UDF doesn't reference user-defined types.
168-
- There are no signatures added to the UDF <sup>9</sup>.
168+
- There are no signatures added to the UDF <sup>9</sup>.
169169
- The UDF isn't a partition function.
170170
- The UDF doesn't contain references to Common Table Expressions (CTEs).
171171
- The UDF doesn't contain references to intrinsic functions that might alter the results when inlined (such as `@@ROWCOUNT`) <sup>4</sup>.
@@ -181,16 +181,6 @@ Requirements of the UDF definition of the UDF, all must be true
181181
- The UDF doesn't contain references to `WITH XMLNAMESPACES` <sup>8</sup>.
182182
- If the UDF definition runs into thousands of lines of code, [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] might choose not to inline it.
183183

184-
Requirement of the execution context all must be true
185-
- The UDF isn't used in `ORDER BY` clause.
186-
- The query invoking a scalar UDF doesn't reference a scalar UDF call in its `GROUP BY` clause.
187-
- The query invoking a scalar UDF in its select list with `DISTINCT` clause doesn't have an `ORDER BY` clause.
188-
- The UDF isn't called from a RETURN statement <sup>6</sup>.
189-
- The query invoking the UDF doesn't have Common Table Expressions (CTEs) <sup>8</sup>.
190-
- The UDF-calling query doesn't use `GROUPING SETS`, `CUBE`, or `ROLLUP` <sup>7</sup>.
191-
- The UDF-calling query doesn't contain a variable that is used as a UDF parameter for assignment (for example, `SELECT @y = 2`, `@x = UDF(@y)`) <sup>7</sup>.
192-
- The UDF isn't used in a computed column or a check constraint definition.
193-
194184
<sup>1</sup> `SELECT` with variable accumulation/aggregation isn't supported for inlining (such as `SELECT @val += col1 FROM table1`).
195185

196186
<sup>2</sup> Recursive UDFs are inlined to a certain depth only.
@@ -207,19 +197,36 @@ Requirement of the execution context all must be true
207197

208198
<sup>8</sup> Restriction added in [!INCLUDE [sql-server-2019](../../includes/sssql19-md.md)] CU 11
209199

210-
<sup>9</sup> Because signatures could be added and dropped after a UDF is created, the decision whether to inline or not is done when the query referencing a scalar UDF is compiled. For example, system functions are typically signed with a certificate. You can use [sys.crypt_properties](../system-catalog-views/sys-crypt-properties-transact-sql.md) to find which objects are signed.
200+
<sup>9</sup> Because signatures could be added and dropped after a UDF is created, the decision whether to inline is done when the query referencing a scalar UDF is compiled. For example, system functions are typically signed with a certificate. You can use [sys.crypt_properties](../system-catalog-views/sys-crypt-properties-transact-sql.md) to find which objects are signed.
201+
202+
All of the following requirement of the *execution context* must be true:
203+
204+
- The UDF isn't used in `ORDER BY` clause.
205+
- The query invoking a scalar UDF doesn't reference a scalar UDF call in its `GROUP BY` clause.
206+
- The query invoking a scalar UDF in its select list with `DISTINCT` clause doesn't have an `ORDER BY` clause.
207+
- The UDF isn't called from a RETURN statement <sup>1</sup>.
208+
- The query invoking the UDF doesn't have common table expressions (CTEs) <sup>3</sup>.
209+
- The UDF-calling query doesn't use `GROUPING SETS`, `CUBE`, or `ROLLUP` <sup>2</sup>.
210+
- The UDF-calling query doesn't contain a variable that is used as a UDF parameter for assignment (for example, `SELECT @y = 2`, `@x = UDF(@y)`) <sup>2</sup>.
211+
- The UDF isn't used in a computed column or a check constraint definition.
212+
213+
<sup>1</sup> Restriction added in [!INCLUDE [sql-server-2019](../../includes/sssql19-md.md)] CU 5
214+
215+
<sup>2</sup> Restriction added in [!INCLUDE [sql-server-2019](../../includes/sssql19-md.md)] CU 6
216+
217+
<sup>3</sup> Restriction added in [!INCLUDE [sql-server-2019](../../includes/sssql19-md.md)] CU 11
211218

212219
For information on the latest T-SQL scalar UDF inlining fixes and changes to inlining eligibility scenarios, see the Knowledge Base article: [FIX: scalar UDF inlining issues in SQL Server 2019](https://support.microsoft.com/help/4538581).
213220

214-
### Check whether or not a UDF can be inlined
221+
### Check whether a UDF can be inlined
215222

216-
For every T-SQL scalar UDF, the [sys.sql_modules](../system-catalog-views/sys-sql-modules-transact-sql.md) catalog view includes a property called `is_inlineable`, which indicates whether a UDF is inlineable or not.
223+
For every T-SQL scalar UDF, the [sys.sql_modules](../system-catalog-views/sys-sql-modules-transact-sql.md) catalog view includes a property called `is_inlineable`, which indicates whether a UDF is inlineable.
217224

218225
The `is_inlineable` property is derived from the constructs found inside the UDF definition. It doesn't check whether the UDF is in fact inlineable at compile time. For more information, see the [conditions for inlining](#requirements).
219226

220-
A value of `1` indicates that it's inlineable, and `0` indicates otherwise. This property has a value of `1` for all inline TVFs as well. For all other modules, the value is `0`.
227+
A value of `1` indicates that the UDF is inlineable, and `0` indicates otherwise. This property has a value of `1` for all inline TVFs as well. For all other modules, the value is `0`.
221228

222-
If a scalar UDF is inlineable, it doesn't imply that it's always inlined. [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] decides (on a per-query, per-UDF basis) whether to inline a UDF or not. Check the lists of requirements above.
229+
If a scalar UDF is inlineable, it doesn't imply that it's always inlined. [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] decides (on a per-query, per-UDF basis) whether to inline a UDF. Refer to the lists of requirements earlier in this article.
223230

224231
```sql
225232
SELECT *
@@ -228,12 +235,12 @@ If a scalar UDF is inlineable, it doesn't imply that it's always inlined. [!INCL
228235
ON cp.major_id = o.object_id;
229236
```
230237

231-
### Check whether inlining has happened or not
238+
### Check whether inlining has happened
232239

233-
If all the preconditions are satisfied and [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] decides to perform inlining, it transforms the UDF into a relational expression. From the query plan, it's easy to figure out whether inlining has occurred:
240+
If all the preconditions are satisfied and [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)] decides to perform inlining, it transforms the UDF into a relational expression. From the query plan, you can figure out whether inlining occurred:
234241

235242
- The plan XML doesn't have a `<UserDefinedFunction>` XML node for a UDF that is inlined successfully.
236-
- Certain XEvents are emitted.
243+
- Certain Extended Events are emitted.
237244

238245
## Enable scalar UDF inlining
239246

@@ -333,7 +340,7 @@ As described in this article, scalar UDF inlining transforms a query with scalar
333340

334341
- If a UDF references built-in functions such as `SCOPE_IDENTITY()`, `@@ROWCOUNT`, or `@@ERROR`, the value returned by the built-in function changes with inlining. This change in behavior is because inlining changes the scope of statements inside the UDF. Starting with [!INCLUDE [sql-server-2019](../../includes/sssql19-md.md)] CU2, inlining is blocked if the UDF references certain intrinsic functions (for example `@@ROWCOUNT`).
335342

336-
- If a variable is assigned with the result of an inlined UDF and it also used as index_column_name in FORCESEEK [Query hints](../../t-sql/queries/hints-transact-sql-query.md), it results in error Msg 8622 indicating that the Query processor couldn't produce a query plan because of the hints defined in the query.
343+
- If a variable is assigned with the result of an inlined UDF and it also used as `index_column_name` in `FORCESEEK` [Query hints](../../t-sql/queries/hints-transact-sql-query.md), it results in error 8622, indicating that the query processor couldn't produce a query plan because of the hints defined in the query.
337344

338345
## Related content
339346

0 commit comments

Comments
 (0)