É bem conhecido que SCHEMABINDING
uma função pode evitar um spool desnecessário nos planos de atualização:
Se você estiver usando UDFs T-SQL simples que não tocam em nenhuma tabela (ou seja, não acessam dados), certifique-se de especificar a
SCHEMABINDING
opção durante a criação das UDFs. Isso tornará os UDFs vinculados ao esquema e garantirá que o otimizador de consulta não gere nenhum operador de spool desnecessário para planos de consulta envolvendo esses UDFs.
Existem outras vantagens de SCHEMABINDING
uma função, mesmo que ela não acesse dados?
Sim.
Deixar de especificar
WITH SCHEMABINDING
significa que o SQL Server ignora as verificações detalhadas que normalmente faz no corpo da função. Ele simplesmente marca a função como acessando dados (conforme mencionado no link fornecido na pergunta).Esta é uma otimização de desempenho. Se não fizesse essa suposição, o SQL Server teria que realizar as verificações detalhadas em cada chamada de função (uma vez que a função não vinculada poderia mudar a qualquer momento).
Existem cinco propriedades de funções importantes:
Por exemplo, considere a seguinte função escalar não vinculada:
Podemos olhar para as cinco propriedades usando uma função de metadados:
As duas propriedades de acesso a dados foram definidas como true e as outras três foram definidas como false .
Isso tem implicações além das esperadas (uso em exibições indexadas ou colunas computadas indexadas, por exemplo).
Efeitos no otimizador de consulta
A propriedade Determinism em particular afeta o otimizador de consulta. Possui regras detalhadas sobre os tipos de reescritas e manipulações que pode realizar, e estas são muito restritas para elementos não determinísticos. Os efeitos colaterais podem ser bastante sutis.
Por exemplo, considere as duas tabelas a seguir:
...e uma consulta que usa a função (conforme definido anteriormente):
O plano de consulta é o esperado, apresentando uma busca na tabela T2:
No entanto, se a mesma consulta lógica for escrita usando uma tabela derivada ou uma expressão de tabela comum:
O plano de execução agora apresenta um scan, com o predicado envolvendo a função preso em um Filter:
Isso também acontece se a tabela derivada ou a expressão de tabela comum for substituída por uma exibição ou função em linha. Uma
FORCESEEK
dica (e outras tentativas semelhantes) não terá sucesso: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 precisaria ser movido para baixo no plano para o acesso aos dados T2. Este movimento é impedido quando a função não é determinística.
Fixar
A correção para este exemplo envolve duas etapas:
WITH SCHEMABINDING
O primeiro passo é trivial. A segunda envolve a remoção da conversão implícita não determinística de string para
datetime
; substituindo-o por um determinísticoCONVERT
. Nenhum dos dois é suficiente por si só .As propriedades da função agora são:
Com o otimizador liberado, todos os exemplos agora produzem o plano de busca desejado .
Observe que usar um
CAST
todatetime
na função não funcionaria, pois não é possível especificar um estilo de conversão nessa sintaxe:Esta definição de função produz o plano de varredura e as propriedades mostram que ele permanece não determinístico: