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 数据访问。当函数不确定时,会阻止这种移动。
此示例的修复包括两个步骤:
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;
Run Code Online (Sandbox Code Playgroud)
函数属性现在是:
优化器释放后,所有示例现在都生成所需的搜索计划。
请注意,在函数中使用CAST
todatetime
将不起作用,因为无法在该语法中指定转换样式:
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)
此函数定义生成扫描计划,并且属性显示它仍然是不确定的: