Incorporation des fonctions UDF scalairesScalar UDF Inlining

S’APPLIQUE À : ouiSQL Server ouiAzure SQL Database nonAzure SQL Data Warehouse nonParallel Data Warehouse APPLIES TO: yesSQL Server yesAzure SQL Database noAzure SQL Data Warehouse noParallel Data Warehouse

Cet article présente l’incorporation (inlining) des fonctions UDF scalaires, une fonctionnalité prise en charge dans la suite des fonctionnalités de traitement intelligent des requêtes.This article introduces Scalar UDF inlining, a feature under the intelligent query processing suite of features. Cette fonctionnalité améliore les performances des requêtes qui appellent des fonctions UDF scalaires dans SQL ServerSQL Server (à partir de SQL Server 2019 - PreviewSQL Server 2019 preview) et SQL DatabaseSQL Database.This feature improves the performance of queries that invoke scalar UDFs in SQL ServerSQL Server (starting with SQL Server 2019 - PreviewSQL Server 2019 preview) and SQL DatabaseSQL Database.

Fonctions UDF (définies par l'utilisateur) scalaires T-SQLT-SQL Scalar User-Defined Functions

Les fonctions définies par l’utilisateur qui sont implémentées dans Transact-SQL et qui retournent une valeur de données unique sont appelées fonctions UDF (définies par l’utilisateur) scalaires T-SQL.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. Les fonctions UDF T-SQL offrent une façon élégante de réutiliser le code et d’assurer la modularité entre les requêtes SQL.T-SQL UDFs are an elegant way to achieve code reuse and modularity across SQL queries. Certains calculs (tels que des règles métier complexes) sont plus faciles à exprimer sous forme de fonctions UDF impératives.Some computations (such as complex business rules) are easier to express in imperative UDF form. Les fonctions UDF favorisent la création d’une logique complexe sans devoir savoir écrire des requêtes SQL complexes.UDFs help in building up complex logic without requiring expertise in writing complex SQL queries.

Performances des fonctions UDF scalairesPerformance of Scalar UDFs

Les fonctions UDF scalaires présentent généralement des performances médiocres pour les raisons suivantes.Scalar UDFs typically end up performing poorly due to the following reasons.

  • Appel itératif : les fonctions UDF sont appelées de façon itérative, une fois par tuple éligible.Iterative invocation: UDFs are invoked in an iterative manner, once per qualifying tuple. Cela implique des coûts supplémentaires de changements de contexte répétés en raison de l’appel de fonction.This incurs additional costs of repeated context switching due to function invocation. En particulier, les fonctions UDF qui exécutent des requêtes SQL dans leur définition sont gravement affectées.Especially, UDFs that execute SQL queries in their definition are severely affected.
  • Absence d’évaluation des coûts : pendant l’optimisation, seuls les opérateurs relationnels sont estimés, tandis que les opérateurs scalaires ne le sont pas.Lack of costing: During optimization, only relational operators are costed, while scalar operators are not. Avant l’introduction des fonctions UDF scalaires, les autres opérateurs scalaires étaient généralement peu coûteux et n’exigeaient pas une évaluation des coûts.Prior to the introduction of scalar UDFs, other scalar operators were generally cheap and did not require costing. L’ajout d’un coût processeur réduit pour une opération scalaire suffisait.A small CPU cost added for a scalar operation was enough. Il existe des scénarios où le coût réel est important et reste pourtant sous-représenté.There are scenarios where the actual cost is significant, and yet still remains underrepresented.
  • Exécution interprétée : les fonctions UDF sont évaluées sous la forme d’un lot d’instructions, exécuté instruction par instruction.Interpreted execution: UDFs are evaluated as a batch of statements, executed statement-by-statement. Chaque instruction proprement dite est compilée et le plan compilé est mis en cache.Each statement itself is compiled, and the compiled plan is cached. Cette stratégie de mise en cache permet d’économiser du temps, car elle évite les recompilations, mais chaque instruction s’exécute de manière isolée.Although this caching strategy saves some time as it avoids recompilations, each statement executes in isolation. Aucune optimisation entre les instructions n’est réalisée.No cross-statement optimizations are carried out.
  • Exécution en série : SQL Server n’autorise pas le parallélisme intra-requête dans des requêtes qui appellent des fonctions UDF.Serial execution: SQL Server does not allow intra-query parallelism in queries that invoke UDFs.

Incorporation automatique des fonctions UDF scalairesAutomatic Inlining of Scalar UDFs

L’objectif de la fonctionnalité d’incorporation des fonctions UDF scalaires consiste à améliorer les performances des requêtes qui appellent des fonctions UDF scalaires T-SQL, lorsque l’exécution des fonctions UDF constitue le principal goulot d’étranglement.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.

Avec cette nouvelle fonctionnalité, les fonctions UDF scalaires sont automatiquement transformées en expressions scalaires ou sous-requêtes scalaires qui sont substituées dans la requête d’appel à la place de l’opérateur UDF.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. Ces expressions et sous-requêtes sont ensuite optimisées.These expressions and subqueries are then optimized. Par conséquent, le plan de requête n’a plus d’opérateur de fonction définie par l’utilisateur, mais ses effets sont observés dans le plan, tels que des vues ou des fonctions table (TVF) inline.As a result, the query plan will no longer have a user-defined function operator, but its effects will be observed in the plan, like views or inline TVFs.

Exemple 1 - Fonction UDF scalaire à instruction uniqueExample 1 - Single statement scalar UDF

Considérez la requête suivante :Consider the following query

SELECT L_SHIPDATE, O_SHIPPRIORITY, SUM (L_EXTENDEDPRICE *(1 - L_DISCOUNT)) 
FROM LINEITEM
INNER JOIN ORDERS
  ON O_ORDERKEY = L_ORDERKEY 
GROUP BY L_SHIPDATE, O_SHIPPRIORITY ORDER BY L_SHIPDATE;

Cette requête calcule la somme des prix avec remise des articles et présente les résultats groupés par date d’expédition et priorité d’expédition.This query computes the sum of discounted prices for line items and presents the results grouped by the shipping date and shipping priority. L’expression L_EXTENDEDPRICE *(1 - L_DISCOUNT) est la formule correspondant au prix avec remise d’un article donné.The expression L_EXTENDEDPRICE *(1 - L_DISCOUNT) is the formula for the discounted price for a given line item. Il est possible d’extraire ces formules dans des fonctions afin d’assurer leur modularité et leur réutilisation.Such formulas can be extracted into functions for the benefit of modularity and reuse.

CREATE FUNCTION dbo.discount_price(@price DECIMAL(12,2), @discount DECIMAL(12,2)) 
RETURNS DECIMAL (12,2) AS
BEGIN
  RETURN @price * (1 - @discount);
END

La requête peut alors être modifiée pour appeler cette fonction UDF.Now the query can be modified to invoke this UDF.

SELECT L_SHIPDATE, O_SHIPPRIORITY, SUM (dbo.discount_price(L_EXTENDEDPRICE, L_DISCOUNT)) 
FROM LINEITEM
INNER JOIN ORDERS
  ON O_ORDERKEY = L_ORDERKEY 
GROUP BY L_SHIPDATE, O_SHIPPRIORITY ORDER BY L_SHIPDATE

Pour les raisons décrites précédemment, la requête avec la fonction UDF présente des performances médiocres.Due to the reasons outlined earlier, the query with the UDF performs poorly. À présent, avec l’incorporation des fonctions UDF scalaires, l’expression scalaire figurant dans le corps de la fonction UDF est substituée directement dans la requête.Now, with scalar UDF inlining, the scalar expression in the body of the UDF is substituted directly in the query. Les résultats de l’exécution de la requête sont affichés dans le tableau ci-dessous :The results of running this query are shown in the below table:

Requête :Query: Requête sans fonction UDFQuery without UDF Requête avec fonction UDF (sans incorporation)Query with UDF (without inlining) Requête avec incorporation des fonctions UDF scalairesQuery with scalar UDF inlining
Durée d’exécution :Execution time: 1,6 seconde1.6 seconds 29 minutes et 11 secondes29 minutes 11 seconds 1,6 seconde1.6 seconds

Ces nombres sont basés sur une base de données CCI de 10 Go (utilisant le schéma TPC-H) en cours d’exécution sur une machine à biprocesseur (12 cœurs) dotée de 96 Go de RAM et soutenue par un disque SSD.These numbers are based on a 10-GB CCI database (using the TPC-H schema), running on a machine with dual processor (12 core), 96-GB RAM, backed by SSD. Ces nombres incluent la durée de compilation et d’exécution avec un pool de mémoires tampons et un cache de procédures à froid.The numbers include compilation and execution time with a cold procedure cache and buffer pool. La configuration par défaut a été utilisée et aucun autre index n’a été créé.The default configuration was used, and no other indexes were created.

Exemple 2 - Fonction UDF scalaire à instructions multiplesExample 2 - Multi-statement scalar UDF

Les fonctions UDF scalaires qui sont implémentées à l’aide de plusieurs instructions T-SQL, telles que les affectations de variables et le branchement conditionnel, peuvent également être incorporées.Scalar UDFs that are implemented using multiple T-SQL statements such as variable assignments and conditional branching can also be inlined. Considérez la fonction UDF scalaire suivante qui, à partir d’une clé client donnée, détermine la catégorie de service pour le client.Consider the following scalar UDF that, given a customer key, determines the service category for that customer. Elle arrive à cette catégorie en calculant au départ le prix total de toutes les commandes passées par le client à l’aide d’une requête SQL.It arrives at the category by first computing the total price of all orders placed by the customer using a SQL query. Ensuite, elle utilise une logique IF-ELSE pour décider de la catégorie en fonction du prix total.Then, it uses an IF-ELSE logic to decide the category based on the total price.

CREATE OR ALTER FUNCTION dbo.customer_category(@ckey INT) 
RETURNS CHAR(10) AS
BEGIN
  DECLARE @total_price DECIMAL(18,2);
  DECLARE @category CHAR(10);

  SELECT @total_price = SUM(O_TOTALPRICE) FROM ORDERS WHERE O_CUSTKEY = @ckey;

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

  RETURN @category;
END

À présent, considérez une requête qui appelle cette fonction UDF.Now, consider a query that invokes this UDF.

SELECT C_NAME, dbo.customer_category(C_CUSTKEY) FROM CUSTOMER;

Le plan d’exécution pour cette requête dans SQL Server 2017 (niveau de compatibilité 140 ou antérieur) est le suivant :The execution plan for this query in SQL Server 2017 (compatibility level 140 and earlier) is as follows:

Plan de requête sans incorporation

Comme le montre le plan, SQL Server adopte une stratégie simple ici : appeler la fonction UDF et fournir les résultats pour chaque tuple figurant dans la table CUSTOMER.As the plan shows, SQL Server adopts a simple strategy here: for every tuple in the CUSTOMER table, invoke the UDF and output the results. Cette stratégie est naïve et inefficace.This strategy is na?ve and inefficient. Avec l’incorporation, ces fonctions UDF sont transformées en sous-requêtes scalaires équivalentes, qui sont substituées dans la requête d’appel à la place de la fonction UDF.With inlining, such UDFs are transformed into equivalent scalar subqueries, which are substituted in the calling query in place of the UDF.

Pour la même requête, le plan avec la fonction UDF incorporée se présente comme suit.For the same query, the plan with the UDF inlined looks as below.

Plan de requête avec incorporation

Comme mentionné précédemment, le plan de requête n’a plus d’opérateur de fonction définie par l’utilisateur, mais ses effets sont désormais observables dans le plan, tels que des vues ou des fonctions table (TVF) inline.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. Voici quelques observations clés tirées du plan ci-dessus :Here are some key observations from the above plan:

  1. SQL Server a déduit la jointure implicite entre CUSTOMER et ORDERS, et l’a rendue explicite via un opérateur de jointure.SQL Server has inferred the implicit join between CUSTOMER and ORDERS and made that explicit via a join operator.
  2. SQL Server a également déduit le GROUP BY O_CUSTKEY on ORDERS implicite et a utilisé IndexSpool + StreamAggregate pour l’implémenter.SQL Server has also inferred the implicit GROUP BY O_CUSTKEY on ORDERS and has used the IndexSpool + StreamAggregate to implement it.
  3. SQL Server utilise désormais le parallélisme entre tous les opérateurs.SQL Server is now using parallelism across all operators.

Nous sommes à votre écoute : Si vous trouvez des informations obsolètes ou incorrectes dans cet article, par exemple une étape ou une erreur dans un code, n’hésitez pas à nous en faire part.We are listening: If you find something outdated or incorrect in this article, such as a step or a code example, please tell us. Vous pouvez cliquer sur le bouton Cette page dans la section Commentaires au bas de cette page.You can click the This page button in the Feedback section at the bottom of this page. Nous lisons chaque commentaire concernant SQL, généralement le jour suivant.We read every item of feedback about SQL, typically the next day. Nous vous remercions.Thanks.

Selon la complexité de la logique dans la fonction UDF, le plan de requête obtenu peut également grandir et se complexifier.Depending upon the complexity of the logic in the UDF, the resulting query plan might also get bigger and more complex. Comme nous pouvons le constater, les opérations au sein de la fonction UDF ne sont plus une boîte noire et, par conséquent, l’optimiseur de requête est en mesure d’évaluer le coût de ces opérations et de les optimiser.As we can see, the operations inside the UDF are now no longer a black box, and hence the query optimizer is able to cost and optimize those operations. En outre, comme la fonction UDF n’est plus dans le plan, l’appel itératif de la fonction UDF est remplacé par un plan qui permet d’éviter toute surcharge d’appel de fonction.Also, since the UDF is no longer in the plan, iterative UDF invocation is replaced by a plan that completely avoids function call overhead.

Exigences des fonctions UDF scalaires incorporablesInlineable Scalar UDFs requirements

Une fonction UDF T-SQL scalaire peut être incorporée si toutes les conditions suivantes sont remplies :A scalar T-SQL UDF can be inline if all of the following conditions are true:

  • La fonction UDF est écrite à l’aide des constructions suivantes :The UDF is written using the following constructs:
    • DECLARE, SET : déclaration et affectations des variables.DECLARE, SET: Variable declaration and assignments.
    • SELECT: requête SQL avec une ou plusieurs affectations de variables1.SELECT: SQL query with single/multiple variable assignments1.
    • IF/ELSE : création de branches avec des niveaux d’imbrication arbitraires.IF/ELSE: Branching with arbitrary levels of nesting.
    • RETURN: une ou plusieurs instructions return.RETURN: Single or multiple return statements.
    • UDF: appels de fonction imbriqués/récursifs2.UDF: Nested/recursive function calls2.
    • Autres : opérations relationnelles telles que EXISTS, ISNULL.Others: Relational operations such as EXISTS, ISNULL.
  • La fonction UDF n’appelle pas de fonction intrinsèque dépendante du temps (telle que GETDATE()) ou ayant des effets secondaires3 (telle que NEWSEQUENTIALID()).The UDF does not invoke any intrinsic function that is either time-dependent (such as GETDATE()) or has side effects3 (such as NEWSEQUENTIALID()).
  • La fonction UDF utilise la clause EXECUTE AS CALLER (comportement par défaut si la clause EXECUTE AS n’est pas spécifiée).The UDF uses the EXECUTE AS CALLER clause (the default behavior if the EXECUTE AS clause is not specified).
  • La fonction UDF ne référence pas de variables de table ni de paramètres table.The UDF does not reference table variables or table-valued parameters.
  • La requête qui appelle une fonction UDF scalaire ne référence pas un appel de fonction UDF scalaire dans sa clause GROUP BY.The query invoking a scalar UDF does not reference a scalar UDF call in its GROUP BY clause.
  • La requête qui appelle une fonction UDF scalaire dans sa liste de sélection avec la clause DISTINCT ne référence pas un appel de fonction UDF scalaire dans sa clause ORDER BY.The query invoking a scalar UDF in its select list with DISTINCT clause does not reference a scalar UDF call in its ORDER BY clause.
  • La fonction UDF n’est pas compilée en mode natif (l’interopérabilité est prise en charge).The UDF is not natively compiled (interop is supported).
  • La fonction UDF n’est pas utilisée dans une colonne calculée ni une définition de contrainte de vérification.The UDF is not used in a computed column or a check constraint definition.
  • La fonction UDF ne référence pas de types définis par l’utilisateur.The UDF does not reference user-defined types.
  • Aucune signature n’est ajoutée à la fonction UDF.There are no signatures added to the UDF.
  • La fonction UDF n’est pas une fonction de partition.The UDF is not a partition function.

1 SELECT avec une accumulation/agrégation de variable (par exemple, SELECT @val += col1 FROM table1) n’est pas pris en charge pour l’incorporation.1 SELECT with variable accumulation/aggregation (for example, SELECT @val += col1 FROM table1) is not supported for inlining.

2 Les fonctions UDF récursives sont incorporées seulement jusqu’à une certaine profondeur.2 Recursive UDFs will be inlined to a certain depth only.

3 Les fonctions intrinsèques dont les résultats dépendent de l’heure système actuelle sont dépendantes de l’heure.3 Intrinsic functions whose results depend upon the current system time are time-dependent. Une fonction intrinsèque qui peut mettre à jour un état global interne est un exemple de fonction avec effets secondaires.An intrinsic function that may update some internal global state is an example of a function with side effects. Ces fonctions retournent des résultats différents chaque fois qu’elles sont appelées, selon l’état interne.Such functions return different results each time they are called, based on the internal state.

Vérification du fait qu’une fonction UDF peut être ou non incorporéeChecking whether or not a UDF can be inlined

Pour chaque fonction UDF scalaire T-SQL, la vue de catalogue sys.sql_modules inclut une propriété appelée is_inlineable, qui indique si une fonction UDF est incorporable ou non.For every T-SQL scalar UDF, the sys.sql_modules catalog view includes a property called is_inlineable, which indicates whether a UDF is inlineable or not. La valeur 1 indique qu’elle est incorporable, et 0 indique le contraire.A value of 1 indicates that it is inlineable, and 0 indicates otherwise. Cette propriété a également la valeur 1 pour toutes les fonctions table inline.This property will have a value of 1 for all inline TVFs as well. Pour tous les autres modules, la valeur est 0.For all other modules, the value will be 0.

Notes

Si une fonction UDF scalaire est incorporable, cela n’implique pas qu’elle sera toujours incorporée.If a scalar UDF is inlineable, it does not imply that it will always be inlined. SQL Server décide (pour chaque requête et chaque fonction UDF) s’il convient d’incorporer une fonction UDF ou non.SQL Server will decide (on a per-query, per-UDF basis) whether to inline a UDF or not. Par exemple, si la définition de la fonction UDF s’exécute dans des milliers de lignes de code, SQL Server peut choisir de ne pas l’incorporer.For instance, if the UDF definition runs into thousands of lines of code, SQL Server might choose not to inline it. Un autre exemple est une fonction UDF dans une clause GROUP BY, qui ne sera pas incorporée.Another example is a UDF in a GROUP BY clause - which will not be inlined. Cette décision est prise lorsque la requête qui référence une fonction UDF scalaire est compilée.This decision is made when the query referencing a scalar UDF is compiled.

Vérification pour déterminer si l’incorporation a ou non eu lieuChecking whether inlining has happened or not

Si toutes les conditions préalables sont remplies et que SQL Server décide d’effectuer l’incorporation, il transforme la fonction UDF en une expression relationnelle.If all the preconditions are satisfied and SQL Server decides to perform inlining, it transforms the UDF into a relational expression. À partir du plan de requête, il est facile de déterminer si l’incorporation a eu lieu ou non :From the query plan, it is easy to figure out whether inlining has happened or not:

  • Le fichier xml du plan n’aura pas de nœud xml <UserDefinedFunction> pour une fonction UDF qui a été incorporée correctement.The plan xml will not have a <UserDefinedFunction> xml node for a UDF that has been inlined successfully.
  • Certains événements XEvents sont émis.Certain XEvents are emitted.

Activation de l’incorporation des fonctions UDF scalairesEnabling scalar UDF inlining

Vous pouvez rendre les charges de travail automatiquement éligibles à l’incorporation des fonctions UDF scalaires en activant le niveau de compatibilité 150 pour la base de données.?You can make workloads automatically eligible for scalar UDF inlining by enabling compatibility level 150 for the database.? Vous pouvez définir cette option à l’aide de Transact-SQL.?Par exemple :You can set this using Transact-SQL.?For example:

ALTER DATABASE [WideWorldImportersDW] SET COMPATIBILITY_LEVEL = 150;

En outre, aucune autre modification des requêtes ou des fonctions UDF n’est requise pour tirer parti de cette fonctionnalité.Apart from this, there are no other changes required to be made to UDFs or queries to take advantage of this feature.

Désactivation de l’incorporation des fonctions UDF scalaires sans modifier le niveau de compatibilitéDisabling Scalar UDF inlining without changing the compatibility level

L’incorporation des fonctions UDF scalaires peut être désactivée au niveau de la portée de la base de données, de l’instruction ou de la fonction UDF, tout en conservant le niveau de compatibilité de base de données 150 ou supérieur.Scalar UDF inlining can be disabled at the database, statement, or UDF scope while still maintaining database compatibility level 150 and higher. Pour désactiver l’incorporation des fonctions UDF scalaires au niveau de la portée de la base de données, exécutez l’instruction suivante dans le contexte de la base de données applicable :To disable scalar UDF inlining at the database scope, execute the following statement within the context of the applicable database:

ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = OFF;

Pour réactiver l’incorporation des fonctions UDF scalaires pour la base de données, exécutez l’instruction suivante dans le contexte de la base de données applicable :To re-enable scalar UDF inlining for the database, execute the following statement within the context of the applicable database:

ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = ON;

Lorsque l'option est activée (ON), ce paramètre apparaît activé dans sys.database_scoped_configurations.When ON, this setting will appear as enabled in sys.database_scoped_configurations. Vous pouvez également désactiver l’incorporation des fonctions UDF scalaires pour une requête spécifique en désignant DISABLE_TSQL_SCALAR_UDF_INLINING comme indicateur de requête USE HINT.You can also disable scalar UDF inlining for a specific query by designating DISABLE_TSQL_SCALAR_UDF_INLINING as a USE HINT query hint. Par exemple :For example:

SELECT L_SHIPDATE, O_SHIPPRIORITY, SUM (dbo.discount_price(L_EXTENDEDPRICE, L_DISCOUNT)) 
FROM LINEITEM
INNER JOIN ORDERS
  ON O_ORDERKEY = L_ORDERKEY 
GROUP BY L_SHIPDATE, O_SHIPPRIORITY ORDER BY L_SHIPDATE
OPTION (USE HINT('DISABLE_TSQL_SCALAR_UDF_INLINING'));

Un indicateur de requête USE HINT est prioritaire par rapport à la configuration étendue à la base de données et par rapport à un paramètre de niveau de compatibilité.A USE HINT query hint takes precedence over the database scoped configuration or compatibility level setting.

L’incorporation des fonctions UDF scalaires peut également être désactivée pour une fonction UDF spécifique à l’aide de la clause INLINE dans l’instruction CREATE FUNCTION ou ALTER FUNCTION.Scalar UDF inlining can also be disabled for a specific UDF using the INLINE clause in the CREATE FUNCTION or ALTER FUNCTION statement. Par exemple :For example:

CREATE OR ALTER FUNCTION dbo.discount_price(@price DECIMAL(12,2), @discount DECIMAL(12,2))
RETURNS DECIMAL (12,2)
WITH INLINE = OFF
AS
BEGIN
    RETURN @price * (1 - @discount);
END

Une fois l’instruction ci-dessus exécutée, cette fonction UDF ne sera jamais incorporée dans aucune requête qui l’appelle.Once the above statement is executed, this UDF will never be inlined into any query that invokes it. Pour réactiver l’incorporation pour cette fonction UDF, exécutez l’instruction suivante :To re-enable inlining for this UDF, execute the following statement:

CREATE OR ALTER FUNCTION dbo.discount_price(@price DECIMAL(12,2), @discount DECIMAL(12,2))
RETURNS DECIMAL (12,2)
WITH INLINE = ON
AS
BEGIN
    RETURN @price * (1 - @discount);
END

Notes

La clause INLINE n'est pas obligatoire.The INLINE clause is not mandatory. Si la clause INLINE n’est pas spécifiée, elle est automatiquement définie sur ON/OFF selon que la fonction UDF peut ou non être incorporée.If INLINE clause is not specified, it is automatically set to ON/OFF based on whether the UDF can be inlined. Si INLINE=ON est spécifié mais que la fonction UDF s’avère inéligible pour l’incorporation, une erreur est levée.If INLINE=ON is specified but the UDF is found ineligible for inlining, an error will be thrown.

Remarques importantesImportant Notes

Comme cela est décrit dans cet article, l’incorporation des fonctions UDF scalaires transforme une requête avec des fonctions UDF scalaires en une requête avec une sous-requête scalaire équivalente.As described in this article, scalar UDF inlining transforms a query with scalar UDFs into a query with an equivalent scalar subquery. En raison de cette transformation, les utilisateurs peuvent remarquer des différences de comportement dans les scénarios suivants :Due to this transformation, users may notice some differences in behavior in the following scenarios:

  1. L’incorporation génère un hachage de requête différent pour le même texte de requête.Inlining will result in a different query hash for the same query text.
  2. Certains avertissements dans les instructions figurant dans la fonction UDF (tels qu’une division par zéro, etc.), qui peuvent avoir été cachés précédemment, peuvent apparaître en raison de l’incorporation.Certain warnings in statements inside the UDF (such as divide by zero etc.) which might have been hidden earlier, might show up due to inlining.
  3. Les indicateurs de jointure au niveau des requêtes ne sont peut-être plus valides, car l’incorporation peut introduire de nouvelles jointures.Query level join hints might not be valid anymore, as inlining may introduce new joins. Les indicateurs de jointure locaux doivent être utilisés à la place.Local join hints will have to be used instead.
  4. Les vues qui référencent des fonctions UDF scalaires inline ne peuvent pas être indexées.Views that reference inline scalar UDFs cannot be indexed. Si vous avez besoin de créer un index sur ces vues, désactivez l’incorporation pour les fonctions UDF référencées.If you need to create an index on such views, disable inlining for the referenced UDFs.
  5. Il peut y avoir des différences de comportement de Dynamic Data Masking avec l’incorporation des données UDF.There might be some differences in the behavior of Dynamic Data masking with UDF inlining. Dans certaines situations (selon la logique utilisée dans la fonction UDF), l’incorporation peut être plus conservatrice que le masquage des colonnes de sortie.In certain situations (depending upon the logic in the UDF), inlining might be more conservative w.r.t masking output columns. Dans les scénarios où les colonnes référencées dans une fonction UDF ne sont pas les colonnes de sortie, elles ne sont pas masquées.In scenarios where the columns referenced in a UDF are not output columns, they will not be masked.
  6. Si une fonction UDF référence des fonctions intégrées telles que SCOPE_IDENTITY(), la valeur retournée par la fonction intégrée change avec l’incorporation.If a UDF references built-in functions such as SCOPE_IDENTITY(), the value returned by the built-in function will change with inlining. Ce changement de comportement est dû au fait que l’incorporation modifie l’étendue des instructions au sein de la fonction UDF.This change in behavior is because inlining changes the scope of statements inside the UDF.

Voir aussiSee Also

Centre de performances pour le moteur de base de données SQL Server et Azure SQL DatabasePerformance Center for SQL Server Database Engine and Azure SQL Database

Guide d’architecture de traitement des requêtesQuery Processing Architecture Guide

Guide de référence des opérateurs Showplan logiques et physiquesShowplan Logical and Physical Operators Reference

JoinsJoins

Illustration du traitement de requêtes adaptatifDemonstrating Adaptive Query Processing