Sql Server детерминированная пользовательская функция - PullRequest
30 голосов
/ 06 сентября 2010

У меня есть следующая пользовательская функция:

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

Я не могу создать индекс для вычисляемого столбца, используя эту функцию, поскольку он не является детерминированным.Кто-то может объяснить, почему он не является детерминированным и, в конце концов, как его изменить, чтобы сделать его детерминированным?Спасибо

Ответы [ 2 ]

46 голосов
/ 06 сентября 2010

Вам просто нужно создать его 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
5 голосов
/ 06 сентября 2010

Вам необходимо объявить пользовательскую функцию 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
...