SCHEMABINDING 万圣节保护之外的功能是否有任何好处?

Pau*_*ite 56 sql-server functions

众所周知,SCHEMABINDING一个函数可以避免更新计划中不必要的假脱机

如果您使用不涉及任何表(即不访问数据)的简单 T-SQL UDF,请确保SCHEMABINDING在创建 UDF 期间指定该选项。这将使 UDF 模式绑定并确保查询优化器不会为涉及这些 UDF 的查询计划生成任何不必要的假脱机运算符。

SCHEMABINDING即使不访问数据,函数还有其他优势吗?

Pau*_*ite 86

是的。

未能指定WITH SCHEMABINDING意味着 SQL Server 会跳过它通常对函数体进行的详细检查。它只是将该函数标记为访问数据(如问题中给出的链接中所述)。

这是性能优化。如果它没有做出这个假设,SQL Server 将不得不对每个函数调用执行详细检查(因为未绑定的函数可能随时更改)。

五个重要的函数属性:

  • 决定论
  • 精确
  • 数据访问
  • 系统数据访问
  • 系统验证

例如,采用以下未绑定的标量函数:

CREATE FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
AS
BEGIN
    RETURN '19000101';
END;
Run Code Online (Sandbox Code Playgroud)

我们可以使用元数据函数查看五个属性:

SELECT 
    IsDeterministic = OBJECTPROPERTYEX(Func.ID, 'IsDeterministic'),
    IsPrecise = OBJECTPROPERTYEX(Func.ID, 'IsPrecise'),
    IsSystemVerified = OBJECTPROPERTYEX(Func.ID, 'IsSystemVerified'),
    UserDataAccess = OBJECTPROPERTYEX(Func.ID, 'UserDataAccess'),
    SystemDataAccess = OBJECTPROPERTYEX(Func.ID, 'SystemDataAccess')
FROM (VALUES(OBJECT_ID(N'dbo.F', N'FN'))) AS Func (ID);
Run Code Online (Sandbox Code Playgroud)

结果

两个数据访问属性已设置为 true ,其他三个设置为 false

这具有超出预期的影响(例如,在索引视图或索引计算列中使用)。

对查询优化器的影响

确定性特别属性会影响查询优化器。它有关于允许执行的重写和操作类型的详细规则,并且这些规则对非确定性元素有很大的限制。副作用可能非常微妙。

例如,请考虑以下两个表:

CREATE TABLE dbo.T1
(
    SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
    SomeDate datetime PRIMARY KEY
);
Run Code Online (Sandbox Code Playgroud)

...以及使用该函数的查询(如之前定义的):

SELECT * 
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON T2.SomeDate = dbo.F(T1.SomeInteger);
Run Code Online (Sandbox Code Playgroud)

查询计划如预期,以查找表 T2 为特色:

寻求计划

但是,如果使用派生表或公用表表达式编写相同的逻辑查询:

WITH CTE AS
(
    SELECT *, dt = dbo.F(T1.SomeInteger) 
    FROM dbo.T1 AS T1
)
SELECT * 
FROM CTE
JOIN dbo.T2 AS T2
    ON T2.SomeDate = CTE.dt;

-- Derived table
SELECT
    *
FROM 
(
    SELECT *, dt = dbo.F(T1.SomeInteger)
    FROM dbo.T1 AS T1
) AS T1
JOIN dbo.T2 AS T2
    ON T2.SomeDate = T1.dt;
Run Code Online (Sandbox Code Playgroud)

执行计划现在具有扫描功能,谓词涉及停留在过滤器中的函数:

扫描计划

如果派生表或公用表表达式被视图或内联函数替换,也会发生这种情况。一个FORCESEEK提示(以及其他类似的尝试)将不会成功:

错误信息

根本问题是查询优化器不能自由地重新排序非确定性查询元素

要产生搜索,过滤谓词需要在计划中向下移动到 T2 数据访问。当函数不确定时,会阻止这种移动。

使固定

此示例的修复包括两个步骤:

  1. 添加 WITH SCHEMABINDING
  2. 使函数具有确定性

第一步是微不足道的。第二个涉及删除从字符串到的非确定性隐式强制转换datetime;用确定性的CONVERT. 两者本身都不够

ALTER FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
    -- Convert with a deterministic style
    RETURN CONVERT(datetime, '19000101', 112);
END;
Run Code Online (Sandbox Code Playgroud)

函数属性现在是:

新房源

优化器释放后,所有示例现在都生成所需的搜索计划


请注意,在函数中使用CASTtodatetime将不起作用,因为无法在该语法中指定转换样式:

ALTER FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
    -- Convert with a deterministic style
    RETURN CAST('19000101' AS datetime);
END;
Run Code Online (Sandbox Code Playgroud)

此函数定义生成扫描计划,并且属性显示它仍然是不确定的:

CAST 函数属性