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


如果您使用的是不触摸任何表(即不访问任何表)的简单T-SQL UDF,数据),请确保在创建UDF时指定了SCHEMABINDING选项。这将使UDF受到模式的约束,并确保查询优化器不会为涉及这些UDF的查询计划生成任何不必要的假脱机操作符。


SCHEMABINDING函数是否还有其他优点,即使不访问数据?

#1 楼

是的。
未能指定WITH SCHEMABINDING意味着SQL Server跳过了它通常对功能主体进行的详细检查。它只是将功能标记为正在访问数据(如问题中给出的链接中所述)。
这是性能优化。如果未做出此假设,则SQL Server将必须对每个函数调用进行详细检查(因为未绑定的函数可能随时更改)。
有五个重要的函数属性:

确定性
精度
数据访问
系统数据访问
系统验证

例如,采用以下未绑定标量函数:
CREATE FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
AS
BEGIN
    RETURN '19000101';
END;

我们可以使用元数据函数查看这五个属性:
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);


两个数据访问属性都设置为true,而其他三个数据访问设置为false。 />这具有超出预期范围的含义(例如,在索引视图或索引的计算列中使用)。
对查询优化器的影响
确定性属性特别影响查询优化器。它具有有关允许执行的重写和操作类型的详细规则,并且这些规则对于非确定性元素非常受限制。副作用可能非常微妙。例如,请考虑以下两个表:
CREATE TABLE dbo.T1
(
    SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
    SomeDate datetime PRIMARY KEY
);

...以及使用该函数(如先前定义)的查询:
SELECT * 
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON T2.SomeDate = dbo.F(T1.SomeInteger);

查询计划符合预期,具有对表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;

执行计划现在具有扫描功能,并且谓词所涉及的功能卡在了Filter中:

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

基本问题是查询优化器无法自由地对不确定性查询元素进行重新排序。
要生成搜索,需要将Filter谓词从计划下移至T2数据访问。当功能不确定时,可以防止这种移动。
修复
此示例的修复包括两个步骤:

添加WITH SCHEMABINDING

函数确定性

第一步很简单。第二个涉及删除从字符串到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;

现在的函数属性是:

释放了优化器后,所有示例现在都可以生成所需的查找计划。

请注意,在函数中使用CASTdatetime无效,因为无法使用该语法指定转换样式:
ALTER FUNCTION dbo.F
(
    @i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
    -- Convert with a deterministic style
    RETURN CAST('19000101' AS datetime);
END;

此函数定义会产生扫描计划,并且属性表明它仍然不确定: