Sim.
Deixar de especificar WITH SCHEMABINDING
significa que o SQL Server ignora as verificações detalhadas que normalmente faz no corpo da função. Simplesmente marca a função como acessando dados (como mencionado no link fornecido na pergunta).
Esta é uma otimização de desempenho. Se não fizesse essa suposição, o SQL Server teria que executar as verificações detalhadas de cada chamada de função (já que a função não acoplada pode ser alterada a qualquer momento).
Existem cinco propriedades importantes da função:
- Determinismo
- Precisão
- Acesso de dados
- Acesso aos dados do sistema
- Verificação do sistema
Por exemplo, considere a seguinte função escalar não acoplada:
CREATE FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
AS
BEGIN
RETURN '19000101';
END;
Podemos observar as cinco propriedades usando uma função de metadados:
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);
As duas propriedades de acesso a dados foram definidas como verdadeiras e as outras três são definidas como falsas .
Isso tem implicações além daquelas que podem ser esperadas (uso em visualizações indexadas ou colunas computadas indexadas, por exemplo).
Efeitos no otimizador de consultas
A propriedade Determinism , em particular, afeta o otimizador de consulta. Possui regras detalhadas sobre os tipos de reescritas e manipulações que é permitido executar e são muito restritas a elementos não determinísticos. Os efeitos colaterais podem ser bastante sutis.
Por exemplo, considere as duas tabelas a seguir:
CREATE TABLE dbo.T1
(
SomeInteger integer PRIMARY KEY
);
GO
CREATE TABLE dbo.T2
(
SomeDate datetime PRIMARY KEY
);
... e uma consulta que usa a função (conforme definido anteriormente):
SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
ON T2.SomeDate = dbo.F(T1.SomeInteger);
O plano de consulta é conforme o esperado, apresentando uma pesquisa na tabela T2:
No entanto, se a mesma consulta lógica for gravada usando uma tabela derivada ou expressão de tabela comum:
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;
O plano de execução agora apresenta uma varredura, com o predicado envolvendo a função travada em um filtro:
Isso também acontece se a tabela derivada ou a expressão comum da tabela for substituída por uma função de exibição ou em linha. Uma FORCESEEK
dica (e outras tentativas semelhantes) não terá êxito:
A questão fundamental é que o otimizador de consulta não pode reordenar elementos de consulta não determinísticos tão livremente .
Para produzir uma busca, o predicado Filtro precisa ser movido para baixo do plano para o acesso a dados T2. Este movimento é evitado quando a função é não determinística.
Consertar
A correção para este exemplo envolve duas etapas:
- Adicionar, acrescentar
WITH SCHEMABINDING
- Tornar a função determinística
O primeiro passo é trivial. O segundo envolve remover a conversão implícita não determinística da string para datetime
; substituindo-o por um determinístico CONVERT
. Nem é suficiente por si só .
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CONVERT(datetime, '19000101', 112);
END;
As propriedades da função são agora:
Com o otimizador liberado, todos os exemplos agora produzem o plano de busca desejado .
Observe que o uso de CAST
a datetime
na função não funcionaria, porque não é possível especificar um estilo de conversão nessa sintaxe:
ALTER FUNCTION dbo.F
(
@i integer
)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
-- Convert with a deterministic style
RETURN CAST('19000101' AS datetime);
END;
Essa definição de função produz o plano de varredura e as propriedades mostram que ele permanece não determinístico: