39

我有以下用户定义的函数:

create function [dbo].[FullNameLastFirst]
(
    @IsPerson bit,
    @LastName nvarchar(100),
    @FirstName nvarchar(100)
)
returns nvarchar(201)
as
begin
    declare @Result nvarchar(201)
    set @Result = (case when @IsPerson = 0 then @LastName else case when @FirstName = '' then @LastName else (@LastName + ' ' + @FirstName) end end)
    return @Result
end

我无法使用此函数在计算列上创建索引,因为它不是确定性的。有人可以解释为什么它不是确定性的,以及最终如何修改以使其具有确定性?谢谢

4

2 回答 2

57

你只需要创建它with schemabinding

SQL Server 然后将验证它是否满足被视为确定性的标准(它这样做是因为它不访问任何外部表或使用非确定性函数,例如getdate())。

您可以验证它是否适用

SELECT OBJECTPROPERTY(OBJECT_ID('[dbo].[FullNameLastFirst]'), 'IsDeterministic')

将模式绑定选项添加到您的原始代码中可以正常工作,但会是一个稍微简单的版本。

CREATE FUNCTION [dbo].[FullNameLastFirst] (@IsPerson  BIT,
                                           @LastName  NVARCHAR(100),
                                           @FirstName NVARCHAR(100))
RETURNS NVARCHAR(201)
WITH SCHEMABINDING
AS
  BEGIN
      RETURN CASE
               WHEN @IsPerson = 0
                     OR @FirstName = '' THEN @LastName
               ELSE @LastName + ' ' + @FirstName
             END
  END
于 2010-09-06T13:07:46.160 回答
10

您需要声明用户定义函数WITH SCHEMABINDING来满足计算列上索引的“确定性”要求。

声明的函数WITH SCHEMABINDING将保留有关函数中使用的对象依赖关系的额外知识(例如表中的列),并将防止对这些列进行任何更改,除非函数本身被预先删除。

确定性函数还可以帮助 Sql Server 优化其执行计划,尤其是万圣节保护问题。

下面是使用模式绑定函数在计算列上创建索引的示例:

create function [dbo].[FullNameLastFirst] 
( 
    @IsPerson bit, 
    @LastName nvarchar(100), 
    @FirstName nvarchar(100) 
) 
returns nvarchar(201) 
with schemabinding
as 
begin 
    declare @Result nvarchar(201) 
    set @Result = (case when @IsPerson = 0 then @LastName 
                        else case when @FirstName = '' then @LastName 
                                  else (@LastName + ' ' + @FirstName) end end) 
    return @Result 
end 


create table Person
(
  isperson bit,
  lastname nvarchar(100),
  firstname nvarchar(100),
  fullname as [dbo].[FullNameLastFirst] (isperson, lastname, firstname)
)
go
insert into person(isperson, lastname, firstname) values (1,'Firstname', 'Surname')
go

create index ix1_person on person(fullname)
go

select fullname from Person with (index=ix1_person) where fullname = 'Firstname Surname'
go
于 2010-09-06T13:14:25.597 回答