Встраивание скалярных пользовательских функцийScalar UDF Inlining

ОБЛАСТЬ ПРИМЕНЕНИЯ: даSQL Server даБаза данных SQL AzureнетХранилище данных SQL AzureнетParallel Data WarehouseAPPLIES TO: yesSQL Server yesAzure SQL Database noAzure SQL Data Warehouse noParallel Data Warehouse

В этой статье приводятся общие сведения о встраивании скалярных пользовательских функций, которое входит в состав набора функций интеллектуальной обработки запросов.This article introduces Scalar UDF inlining, a feature under the intelligent query processing suite of features. Эта функция повышает производительность запросов, вызывающих скалярные пользовательские функции, в SQL ServerSQL Server (начиная с SQL Server 2019 (15.x)SQL Server 2019 (15.x)) и База данных SQLSQL Database.This feature improves the performance of queries that invoke scalar UDFs in SQL ServerSQL Server (starting with SQL Server 2019 (15.x)SQL Server 2019 (15.x)) and База данных SQLSQL Database.

Скалярные пользовательские функции T-SQLT-SQL Scalar User-Defined Functions

Пользовательские функции, которые реализованы на языке Transact-SQL и возвращают одно значение, называются скалярными пользовательскими функциями 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. Это элегантное решение для обеспечения повторного использования и модульности кода SQL-запросов.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. Такие функции позволяют конструировать комплексную логику, не имея опыта в написании сложных SQL-запросов.UDFs help in building up complex logic without requiring expertise in writing complex SQL queries.

Производительность скалярных пользовательских функцийPerformance of Scalar UDFs

Как правило, производительность скалярных пользовательских функций оказывается невысокой по указанным ниже причинам.Scalar UDFs typically end up performing poorly due to the following reasons.

  • Итеративные вызовы. Пользовательские функции вызываются итеративно — однократно в соответствующем кортеже.Iterative invocation: UDFs are invoked in an iterative manner, once per qualifying tuple. Постоянные переключения контекста при вызове функций требуют дополнительных ресурсов.This incurs additional costs of repeated context switching due to function invocation. Особенно это проявляется в случаях, когда SQL-запросы выполняются в определении пользовательской функции.Especially, UDFs that execute SQL queries in their definition are severely affected.
  • Отсутствие оценки затрат. Во время оптимизации оцениваются только реляционные операторы, но не скалярные.Lack of costing: During optimization, only relational operators are costed, while scalar operators are not. До появления скалярных пользовательских функций скалярные операторы, как правило, были нетребовательны к ресурсам и не нуждались в оценке.Prior to the introduction of scalar UDFs, other scalar operators were generally cheap and did not require costing. Достаточно было учитывать небольшое увеличение загрузки ЦП.A small CPU cost added for a scalar operation was enough. Ниже представлены сценарии, в которых фактические затраты значительны, но по-прежнему не принимаются во внимание в полной мере.There are scenarios where the actual cost is significant, and yet still remains underrepresented.
  • Выполнение, ориентированное на интерпретацию. Пользовательские функции оцениваются как пакеты инструкций, но инструкции выполняются поочередно.Interpreted execution: UDFs are evaluated as a batch of statements, executed statement-by-statement. Каждая инструкция компилируется отдельно, а затем скомпилированный план кэшируется.Each statement itself is compiled, and the compiled plan is cached. Хотя такая стратегия кэширования позволяет избежать повторной компиляции и немного сэкономить время, каждая инструкция выполняется изолированно.Although this caching strategy saves some time as it avoids recompilations, each statement executes in isolation. Перекрестная оптимизация инструкций не производится.No cross-statement optimizations are carried out.
  • Последовательное выполнение. В SQL Server не допускается параллелизм внутри запросов, вызывающих пользовательские функции.Serial execution: SQL Server does not allow intra-query parallelism in queries that invoke UDFs.

Автоматическое встраивание скалярных пользовательских функцийAutomatic Inlining of Scalar UDFs

Цель встраивания скалярных пользовательских функций заключается в повышении производительности запросов, которые вызывают скалярные пользовательские функции T-SQL, являющиеся основным узким местом.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.

Эта новая функция автоматически преобразует скалярные пользовательские функции в скалярные выражения или скалярные вложенные запросы, которые подставляются в вызывающий запрос вместо оператора пользовательской функции.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 will no longer have a user-defined function operator, but its effects will be observed in the plan, like views or inline TVFs.

Пример 1. Скалярная пользовательская функция с одной инструкциейExample 1 - Single statement scalar UDF

Рассмотрим следующий запрос.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;

Он вычисляет сумму цен на позиции с учетом скидок и выводит результаты с группировкой по дате и приоритету отгрузки.This query computes the sum of discounted prices for line items and presents the results grouped by the shipping date and shipping priority. Выражение L_EXTENDEDPRICE *(1 - L_DISCOUNT) служит для расчета цены позиции со скидкой.The expression L_EXTENDEDPRICE *(1 - L_DISCOUNT) is the formula for the discounted price for a given line item. Выделение таких формул в отдельные функции позволяет повысить модульность кода и упрощает его повторное использование.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

Теперь запрос можно изменить так, чтобы в нем вызывалась эта пользовательская функция.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

По изложенным выше причинам запрос с пользовательской функцией выполняется медленно.Due to the reasons outlined earlier, the query with the UDF performs poorly. Однако благодаря встраиванию скалярных пользовательских функций скалярное выражение из тела пользовательской функции подставляется непосредственно в запрос.Now, with scalar UDF inlining, the scalar expression in the body of the UDF is substituted directly in the query. Результаты выполнения этого запроса показаны в приведенной ниже таблице.The results of running this query are shown in the below table:

Запрос:Query: Запрос без пользовательской функцииQuery without UDF Запрос с пользовательской функцией (без встраивания)Query with UDF (without inlining) Запрос со встраиванием скалярной пользовательской функцииQuery with scalar UDF inlining
Время выполнения:Execution time: 1,6 секунды1.6 seconds 29 минут 11 секунд29 minutes 11 seconds 1,6 секунды1.6 seconds

Эти показатели получены для базы данных CCI размером 10 ГБ (использующей схему TPC-H), которая размещена на компьютере с двумя процессорами (12 ядер), 96 ГБ ОЗУ и дисками 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. В них было учтено время компиляции и выполнения с холодным кэшем процедур и буферным пулом.The numbers include compilation and execution time with a cold procedure cache and buffer pool. Использовалась конфигурация по умолчанию. Другие индексы не создавались.The default configuration was used, and no other indexes were created.

Пример 2. Скалярная пользовательская функция с несколькими инструкциямиExample 2 - Multi-statement scalar UDF

Скалярные пользовательские функции, которые реализуются с помощью нескольких инструкций T-SQL, таких как присвоение значений переменным и условное ветвление, также могут встраиваться.Scalar UDFs that are implemented using multiple T-SQL statements such as variable assignments and conditional branching can also be inlined. Рассмотрим приведенную ниже скалярную пользовательскую функцию, которая на основе ключа клиента определяет для него категорию обслуживания.Consider the following scalar UDF that, given a customer key, determines the service category for that customer. Для этого она сначала вычисляет общую стоимость всех заказов, размещенных клиентом, с помощью SQL-запроса.It arrives at the category by first computing the total price of all orders placed by the customer using a SQL query. Затем на основе общей стоимости определяется категория посредством логики IF-ELSE.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

Теперь рассмотрим запрос, вызывающий эту пользовательскую функцию.Now, consider a query that invokes this UDF.

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

План выполнения для этого запроса в SQL Server 2017 (уровень совместимости 140 и ниже) выглядит так:The execution plan for this query in SQL Server 2017 (compatibility level 140 and earlier) is as follows:

План запроса без встраивания

Как видно из плана, в SQL Server применяется простая стратегия: для каждого кортежа в таблице 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. Такой подход примитивен и неэффективен.This strategy is naive and inefficient. Благодаря встраиванию подобные пользовательские функции преобразуются в эквивалентные скалярные вложенные запросы, которые подставляются в вызывающий запрос вместо пользовательской функции.With inlining, such UDFs are transformed into equivalent scalar subqueries, which are substituted in the calling query in place of the UDF.

Для этого же запроса план со встроенной пользовательской функцией выглядит так:For the same query, the plan with the UDF inlined looks as below.

План запроса со встраиванием

Как уже говорилось, в плане запроса теперь нет оператора пользовательской функции, но логика функции сохраняется в виде представлений или встроенных функций с табличными значениями.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 above plan:

  1. Сервер SQL Server определил наличие неявного соединения между CUSTOMER и ORDERS и сделал его явным с помощью оператора соединения.SQL Server has inferred the implicit join between CUSTOMER and ORDERS and made that explicit via a join operator.
  2. Сервер SQL Server определил наличие неявного предложения GROUP BY O_CUSTKEY on ORDERS и реализовал его с помощью IndexSpool и StreamAggregate.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 is now using parallelism across all operators.

Мы слушаем! Если вы обнаружили в этой статье устаревшие или недостоверные сведения, например инструкции или пример кода, сообщите нам.We are listening: If you find something outdated or incorrect in this article, such as a step or a code example, please tell us. Можно воспользоваться кнопкой Эта страница в разделе Отзывы внизу страницы.You can click the This page button in the Feedback section at the bottom of this page. Обычно мы читаем отзывы про материалы по SQL на следующий день.We read every item of feedback about SQL, typically the next day. Благодарим вас.Thanks.

В зависимости от сложности логики в пользовательской функции план запроса также может быть больше и сложнее.Depending upon the complexity of the logic in the UDF, the resulting query plan might also get bigger and more complex. Как видите, операции внутри пользовательской функции теперь прозрачны, поэтому оптимизатор запросов может оценить затраты и оптимизировать их.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. Кроме того, так как в плане больше нет пользовательской функции, полностью устраняются накладные расходы, связанные с ее итеративными вызовами.Also, since the UDF is no longer in the plan, iterative UDF invocation is replaced by a plan that completely avoids function call overhead.

Требования к встраиваемым скалярным пользовательским функциямInlineable Scalar UDFs requirements

Скалярную пользовательскую функцию T-SQL можно встраивать, если выполняются все перечисленные ниже условия.A scalar T-SQL UDF can be inline if all of the following conditions are true:

  • Функция написана с использованием следующих конструкций:The UDF is written using the following constructs:
    • DECLARE, SET: объявление переменных и присвоение им значений;DECLARE, SET: Variable declaration and assignments.
    • SELECT: SQL-запрос с присвоением значений одной переменной или нескольким 1;SELECT: SQL query with single/multiple variable assignments1.
    • IF/ELSE: ветвление с произвольными уровнями вложенности;IF/ELSE: Branching with arbitrary levels of nesting.
    • RETURN: одна инструкция return или несколько;RETURN: Single or multiple return statements.
    • UDF: вызовы вложенных или рекурсивных функций 2;UDF: Nested/recursive function calls2.
    • прочее: реляционные операции, такие как EXISTS и ISNULL.Others: Relational operations such as EXISTS, ISNULL.
  • Пользовательская функция не вызывает встроенные функции, которые зависят от времени (например, GETDATE()) или имеют побочные эффекты 3 (например, NEWSEQUENTIALID()).The UDF does not invoke any intrinsic function that is either time-dependent (such as GETDATE()) or has side effects3 (such as NEWSEQUENTIALID()).
  • В функции используется предложение EXECUTE AS CALLER (поведение предложения EXECUTE AS по умолчанию не определено).The UDF uses the EXECUTE AS CALLER clause (the default behavior if the EXECUTE AS clause is not specified).
  • Функция не ссылается на табличные переменные или параметры с табличными значениями.The UDF does not reference table variables or table-valued parameters.
  • В запросе, вызывающем скалярную пользовательскую функцию, вызов такой функции не указан в предложении GROUP BY.The query invoking a scalar UDF does not reference a scalar UDF call in its GROUP BY clause.
  • В запросе, вызывающем скалярную пользовательскую функцию в своем списке выборки с предложением DISTINCT, нет предложения ORDER BY.The query invoking a scalar UDF in its select list with DISTINCT clause does not have ORDER BY clause.
  • UDF не используется в предложении ORDER BY.The UDF is not used in ORDER BY clause.
  • Функция не скомпилирована в собственном коде (поддерживается взаимодействие).The UDF is not natively compiled (interop is supported).
  • Функция не используется в определении вычисляемого столбца или ограничения CHECK.The UDF is not used in a computed column or a check constraint definition.
  • Функция не ссылается на пользовательские типы.The UDF does not reference user-defined types.
  • В функцию не добавлены сигнатуры.There are no signatures added to the UDF.
  • Функция не является функцией секционирования.The UDF is not a partition function.

1 Встраивание инструкций SELECT с накоплением или агрегированием переменных (например, SELECT @val += col1 FROM table1) не поддерживается.1 SELECT with variable accumulation/aggregation (for example, SELECT @val += col1 FROM table1) is not supported for inlining.

2 Рекурсивные пользовательские функции встраиваются только до определенной глубины.2 Recursive UDFs will be inlined to a certain depth only.

3 Зависимыми от времени являются такие встроенные функции, результаты которых зависят от текущего системного времени.3 Intrinsic functions whose results depend upon the current system time are time-dependent. Примером встроенной функции с побочными эффектами служит функция, которая может изменять некоторое внутреннее глобальное состояние.An intrinsic function that may update some internal global state is an example of a function with side effects. Такие функции возвращают разные результаты в зависимости от внутреннего состояния.Such functions return different results each time they are called, based on the internal state.

Проверка возможности встраивания пользовательской функцииChecking whether or not a UDF can be inlined

Для каждой скалярной пользовательской функции T-SQL представление каталога sys.sql_modules содержит свойство is_inlineable, которое указывает, является ли эта функция встраиваемой.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. Значение 1 указывает, что она встраиваемая, а значение 0 — не встраиваемая.A value of 1 indicates that it is inlineable, and 0 indicates otherwise. Это свойство также имеет значение 1 для всех встроенных функций с табличными значениями.This property will have a value of 1 for all inline TVFs as well. Для остальных модулей значение будет равно 0.For all other modules, the value will be 0.

Примечание

Если скалярная пользовательская функция является встраиваемой, это не означает, что она обязательно будет встроенной.If a scalar UDF is inlineable, it does not imply that it will always be inlined. Целесообразность встраивания определяется в SQL Server для каждого конкретного запроса и каждой функции.SQL Server will decide (on a per-query, per-UDF basis) whether to inline a UDF or not. Например, если определение пользовательской функции состоит из тысяч строк кода, возможно, она не будет встраиваться.For instance, if the UDF definition runs into thousands of lines of code, SQL Server might choose not to inline it. Другой пример — пользовательская функция в предложении GROUP BY. Она встраиваться не будет.Another example is a UDF in a GROUP BY clause - which will not be inlined. Решение принимается при компиляции запроса, ссылающегося на скалярную пользовательскую функцию.This decision is made when the query referencing a scalar UDF is compiled.

Проверка применения встраиванияChecking whether inlining has happened or not

Если все предварительные условия соблюдены и сервер SQL Server решает выполнить встраивание, пользовательская функция преобразуется в реляционное выражение.If all the preconditions are satisfied and SQL Server decides to perform inlining, it transforms the UDF into a relational expression. По плану запроса можно легко выяснить, произошло ли встраивание.From the query plan, it is easy to figure out whether inlining has happened or not:

  • В коде XML плана не будет узла <UserDefinedFunction> для успешно встроенной функции.The plan xml will not have a <UserDefinedFunction> xml node for a UDF that has been inlined successfully.
  • Создается ряд событий XEvent.Certain XEvents are emitted.

Включение встраивания скалярных пользовательских функцийEnabling scalar UDF inlining

Рабочие нагрузки можно автоматически сделать подходящими для встраивания скалярных пользовательских функций, включив для базы данных уровень совместимости 150.You can make workloads automatically eligible for scalar UDF inlining by enabling compatibility level 150 for the database.? Это можно сделать с помощью Transact-SQL, например так:You can set this using Transact-SQL.?For example:

ALTER DATABASE [WideWorldImportersDW] SET COMPATIBILITY_LEVEL = 150;

Для использования этой функции других изменений в пользовательские функции или запросы вносить не требуется.Apart from this, there are no other changes required to be made to UDFs or queries to take advantage of this feature.

Отключение встраивания скалярных пользовательских функций без изменения уровня совместимостиDisabling Scalar UDF inlining without changing the compatibility level

Встраивание скалярных пользовательских функций можно отключить в области базы данных, инструкции или пользовательской функции, сохранив уровень совместимости базы данных 150 или более высокий.Scalar UDF inlining can be disabled at the database, statement, or UDF scope while still maintaining database compatibility level 150 and higher. Чтобы отключить встраивание в области базы данных, выполните следующую инструкцию в контексте соответствующей базы данных.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;

Чтобы снова включить встраивание для базы данных, выполните следующую инструкцию в контексте соответствующей базы данных.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;

Когда этот параметр включен, он имеет соответствующее состояние в представлении sys.database_scoped_configurations.When ON, this setting will appear as enabled in sys.database_scoped_configurations. Вы также можете отключить встраивание скалярных пользовательских функций для определенного запроса, назначив DISABLE_TSQL_SCALAR_UDF_INLINING в качестве указания запроса 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. Пример: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'));

Указание запроса USE HINT имеет приоритет над конфигурацией, областью действия которой является база данных, или уровнем совместимости.A USE HINT query hint takes precedence over the database scoped configuration or compatibility level setting.

Встраивание скалярных пользовательских функций можно также отключить для определенной пользовательской функции с помощью предложения INLINE в инструкции CREATE FUNCTION или 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. Пример: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

После выполнения этой инструкции данная пользовательская функция никогда не будет встраиваться в вызывающие ее запросы.Once the above statement is executed, this UDF will never be inlined into any query that invokes it. Чтобы повторно включить встраивание для пользовательской функции, выполните следующую инструкцию.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

Примечание

Предложение INLINE не является обязательным.The INLINE clause is not mandatory. Если INLINE предложение не указано, оно автоматически принимает состояние ON/ или OFF в зависимости от возможности встраивания пользовательской функции.If INLINE clause is not specified, it is automatically set to ON/OFF based on whether the UDF can be inlined. Если указано INLINE=ON, но функция не подходит для встраивания, происходит ошибка.If INLINE=ON is specified but the UDF is found ineligible for inlining, an error will be thrown.

Важные примечанияImportant Notes

Как уже говорилось в этой статье, при встраивании скалярных пользовательских функций запрос с такими функциями преобразуется в запрос с эквивалентными скалярными вложенными запросами.As described in this article, scalar UDF inlining transforms a query with scalar UDFs into a query with an equivalent scalar subquery. Из-за этого пользователи могут заметить отличия в поведении в описанных ниже ситуациях.Due to this transformation, users may notice some differences in behavior in the following scenarios:

  1. В результате встраивания хэш запроса для того же текста запроса будет другим.Inlining will result in a different query hash for the same query text.
  2. В инструкциях внутри пользовательской функции могут появляться предупреждения (например, о делении на ноль и другие), которые были скрыты до встраивания.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. Указания соединения на уровне запроса могут стать недействительными, так как в результате встраивания могут появиться новые соединения.Query level join hints might not be valid anymore, as inlining may introduce new joins. Вместо этого следует использовать локальные указания соединения.Local join hints will have to be used instead.
  4. Невозможно проиндексировать представления, ссылающиеся на встроенные скалярные пользовательские функции.Views that reference inline scalar UDFs cannot be indexed. Чтобы создать индекс для таких представлений, отключите встраивание для соответствующих пользовательских функций.If you need to create an index on such views, disable inlining for the referenced UDFs.
  5. При встраивании пользовательских функций может изменяться поведение динамического маскирования данных.There might be some differences in the behavior of Dynamic Data masking with UDF inlining. В некоторых ситуациях (в зависимости от логики в пользовательской функции) встраивание может быть более консервативным по сравнению с маскированием выходных столбцов.In certain situations (depending upon the logic in the UDF), inlining might be more conservative w.r.t masking output columns. Если столбцы, на которые ссылается пользовательская функция, не являются выходными, они не маскируются.In scenarios where the columns referenced in a UDF are not output columns, they will not be masked.
  6. Если пользовательская функция ссылается на встроенные функции, такие как SCOPE_IDENTITY(), значение, возвращаемое встроенной функцией, меняется после встраивания пользовательской функции.If a UDF references built-in functions such as SCOPE_IDENTITY(), the value returned by the built-in function will change with inlining. Связано это с тем, что встраивание меняет область инструкций внутри пользовательской функции.This change in behavior is because inlining changes the scope of statements inside the UDF.

См. также:See Also

Центр производительности для базы данных SQL Azure и ядра СУБД SQL ServerPerformance Center for SQL Server Database Engine and Azure SQL Database

Руководство по архитектуре обработки запросовQuery Processing Architecture Guide

Справочник по логическим и физическим операторам ShowplanShowplan Logical and Physical Operators Reference

JoinsJoins

Демонстрация адаптивной обработки запросовDemonstrating Adaptive Query Processing