Existe uma maneira de impedir que UDFs escalares em colunas computadas inibam o paralelismo?

29

Muito foi escrito sobre os perigos das UDFs escalares no SQL Server. Uma pesquisa casual retornará grande quantidade de resultados.

Existem alguns lugares onde uma UDF escalar é a única opção.

Como exemplo: ao lidar com XML: XQuery não pode ser usado como uma definição de coluna calculada. Uma opção documentada pela Microsoft é usar um UDF escalar para encapsular seu XQuery em um UDF escalar e usá-lo em uma coluna computada.

Isso tem vários efeitos e algumas soluções alternativas.

  • Executa linha por linha quando a tabela é consultada
  • Força todas as consultas na tabela a serem executadas em série

Você pode contornar a execução linha a linha vinculando o esquema à função e persistindo na coluna computada ou indexando-a. Nenhum desses métodos pode impedir que a serialização forçada de consultas chegue à tabela, mesmo quando o UDF escalar não é referenciado.

Existe uma maneira conhecida de fazer isso?

Erik Darling
fonte

Respostas:

31

Sim se você:

  • estão executando o SQL Server 2014 ou posterior; e
  • são capazes de executar a consulta com o sinalizador de rastreamento 176 ativo; e
  • a coluna computada é PERSISTED

Especificamente, são necessárias pelo menos as seguintes versões :

  • Atualização cumulativa 2 para SQL Server 2016 SP1
  • Atualização cumulativa 4 para o SQL Server 2016 RTM
  • Atualização cumulativa 6 para SQL Server 2014 SP2

MAS, para evitar um bug (ref para 2014 e 2016 e 2017 ) introduzido nessas correções, aplique:

O sinalizador de rastreamento é eficaz como uma –Topção de inicialização , no escopo global e da sessão DBCC TRACEON, usando e por consulta OPTION (QUERYTRACEON)ou um guia de plano.

O sinalizador de rastreamento 176 impede a expansão persistente da coluna computada.

O carregamento inicial de metadados realizado ao compilar uma consulta traz todas as colunas, não apenas aquelas diretamente referenciadas. Isso disponibiliza todas as definições de coluna computadas para correspondência, o que geralmente é uma coisa boa.

Como um efeito colateral infeliz, se uma das colunas carregadas (computadas) usar uma função escalar definida pelo usuário, sua presença desabilitará o paralelismo para toda a consulta, mesmo quando a coluna computada não for realmente usada .

O sinalizador de rastreamento 176 ajuda com isso, se a coluna persistir, não carregando a definição (já que a expansão é ignorada). Dessa forma, uma função escalar definida pelo usuário nunca está presente na árvore de consulta de compilação, portanto, o paralelismo não é desativado.

A principal desvantagem do sinalizador de rastreamento 176 (além de ser documentado apenas levemente) é que também evita que a expressão de consulta corresponda a colunas computadas persistentes: se a consulta contiver uma expressão correspondente a uma coluna computada persistente, o sinalizador de rastreamento 176 impedirá que a expressão seja substituída por uma referência à coluna computada.

Para obter mais detalhes, consulte o artigo SQLPerformance.com, Colunas computadas adequadamente persistidas .

Como a pergunta menciona XML, como alternativa à promoção de valores usando uma coluna computada e uma função escalar, você também pode usar um Índice XML Seletivo, como você escreveu em Índices Seletivos XML: Nada mau .

Paul White diz que a GoFundMonica
fonte
10

Além do excelente Sim # 1 de @ Paul , existe um Sim # 2 que:

  • funciona desde o SQL Server 2005,
  • não requer a configuração de um sinalizador de rastreamento,
  • que não exigem que a coluna computada ser PERSISTED, e
  • (devido à falta de sinalizador de rastreamento 176), não impede a correspondência da expressão de consulta com colunas computadas persistentes

Os únicos inconvenientes (até onde eu sei) são:

  • não funciona no banco de dados SQL do Azure (pelo menos ainda não, embora funcione no Amazon RDS SQL Server e no SQL Server no Linux) e
  • está um pouco fora da zona de conforto de muitos DBA

E esta opção é: SQLCLR

Está certo. Um aspecto legal do SQLCLR Scalar UDFs é que, se eles não fazem qualquer acesso a dados (nem usuário nem do sistema), então eles não proíbem paralelismo. E isso não é apenas teoria ou marketing. Embora eu não tenha tempo (no momento) para fazer a redação totalmente detalhada, testei e provei isso.

Usei a configuração inicial da seguinte postagem no blog (espero que o OP não considere isso uma fonte não confiável 🙃):

Jeans Bad Idea: várias dicas de índice

E realizou os seguintes testes:

  1. Executou a consulta inicial como está ─⇾ Paralelismo (conforme o esperado)
  2. Adicionada uma coluna computada não persistente definida como ([c2] * [c3])─⇾ Paralelismo (conforme o esperado)
  3. Removida a coluna computada e adicionada uma coluna computada não persistente que referenciava uma UDF escalar T-SQL (criada com SCHEMABINDING) definida como RETURN (@First * @Second);─⇾ SEM paralelismo (conforme o esperado)
  4. Removida a coluna computada T-SQL UDF e adicionada uma coluna calculada não persistente que referenciava uma UDF escalar SQLCLR (tentada com ambos IsDeterministic = truee = false) definida como return SqlInt32.Multiply(First, Second);─⇾ Paralelismo (woo hoo !!)

Portanto, embora o SQLCLR não funcione para todos, certamente tem suas vantagens para as pessoas / situações / ambientes que são adequados. E, no que se refere a essa pergunta específica - o exemplo dado ao uso do XQuery -, certamente funcionaria para isso (e, dependendo do que está sendo feito especificamente, pode ser até um pouco mais rápido).

Solomon Rutzky
fonte