Clique no banner para conhecer e adquirir o meu treinamento de Bancos de Dados no Azure

SQL Server – Comparação de performance entre Scalar Function e CLR Scalar Function

Post Views 1,984 views
Esse post é a parte 5 de 10 da série Performance Tuning
Reading time 13 minutes

Olá pessoal,
Tudo bem com vocês ??

Neste post, que será o número 200 do blog, eu gostaria de falar sobre dois assuntos que eu particularmente gosto muito no SQL Server, que é a criação de rotinas .NET (CLR) dentro do banco de dados SQL Server e performance tuning.

Coincidência ou não, meu post de número 100 foi o Introdução ao SQL CLR (Common Language Runtime) no SQL Server, que foi o meu primeiro post no blog sobre o CLR.

Meu intuito nesse post, é demonstrar o ganho de performance que pode ser obtido ao utilizar Scalar functions do CLR ao invés da Scalar function escrita em T-SQL (UDF – User Defined Function). Nos testes realizados, a grande maioria das funções T-SQL que foram migradas para funções CLR tiverem um grande ganho de performance simplesmente por conta das otimizações do Microsoft .NET Framework frente ao motor do SQL Server.

Em muitas situações, vemos que os índices estão criados corretamente, estatísticas atualizadas e, sem precisar reescrever a query, pode-se conseguir um grande ganho de performance simplesmente alterando a linguagem de programação de funções escalares.

Função no CLR sempre vai ser melhor?

Há quem possa ter algumas dúvidas sobre a performance de funções escalares do CLR, as quais vou esclarecer:

– As funções escalares do CLR sempre vão ter uma performance melhor que funções ?
Com certeza não! Já fiz vários testes comparando diversas funções, de diversas finalidades diferentes e pela minha experiência, as funções scalares escritas em C# no CLR, GERALMENTE apresentam sim, uma melhor performance, mas já vi alguns casos em que mesmo otimizando o código ao máximo, a função T-SQL apresenta um desempenho melhor.

– E se compararmos a performance de funções nativas com as funções do CLR ?
Funções, de uma maneira geral, sempre prejudicam a performance se uma consulta ao banco de dados. Entretanto, por mais que as funções escalares do CLR sejam bem performáticas, GERALMENTE as funções nativas do SQL Server (Ex: CONVERT, CAST, DATEADD, etc) apresentam uma melhor performance quando comparadas.

Comparando a performance na prática

Depois de fazer essa introdução sobre o assunto, é hora de realmente demonstrar o que foi falado aqui. E nada melhor que realizar os testes de performance na prática para convencer você, de que o CLR pode, em muitos casos, prover um grande ganho de performance nas suas consultas ao SQL Server.

Para gerar a massa de dados de testes, utilizei esse script:

O código-fonte da função fncRand(), bem como a explicação de porque utilizo essa função ao invés da RAND(), você encontra no post SQL Server – Msg 443 Invalid use of a side-effecting operator ‘rand’ within a function.

fncPrimeiroDiaMes

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

Comparação de performance no WHERE

fncUltimoDiaMes

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

Comparação de performance no WHERE

fncSplit

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT
Reparem que, após esperar 5 mins, acabei cancelando e iniciando os testes novamente, mas com apenas 10.000 registros para a função T-SQL, comparando com a função do CLR rodando em 100.000 registros. Mas mesmo a função do CLR sendo executada 10x mais, vejam o que aconteceu nos resultados…

Comparação de performance no WHERE

fncBase64_Encode

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

fncBase64_Decode

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

fncValida_CPF

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

fncRecupera_Numeros

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

fncMes

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

fncConverte_Em_Horas

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

fncFormata_Documento

Visualizar conteúdo
Código-fonte T-SQL:

Código-fonte CLR:

Saída:

Comparação de performance no SELECT

Conclusão

Após 10 testes de performance entre Scalar functions T-SQL x CLR, pode-se chegar a conclusão que em todos os casos apresentados (escolhi 10 de 90 funções que tenho nas 2 linguagens, aleatoriamente), a função CLR teve um enorme ganho de performance, tanto de CPU quanto de tempo de execução. Na empresa onde atuo como DBA, fiz o teste em todas as 90 funções e em 87 casos, a função escrita em C# foi executada em, no mínimo, a metade do tempo da função T-SQL.

Entretanto, conforme já falei acima, isso não quer dizer que em 100% dos casos isso irá ocorrer. Como tudo relacionado à performance tuning, não existe uma dica perfeita que se aplica a 100% das situações. Antes de alterar uma função T-SQL para SQL, faça vários testes para garantir que realmente houve um ganho expressivo de performance ao criar a função no CLR.

Nos primeiros 2 exemplos, onde as funções são bem simples, pude comparar também com as funções nativas do SQL Server, sem o uso de funções UDF. Neste casos, foi possível observar que sem utilizar função UDF e aplicando as funções nativas diretamente no SELECT e/ou WHERE, ela acaba sendo mais rápida até que o CLR. Entretanto, muitas vezes, as funções são bastante complexas, o que acaba dificultando e até impossibilitando o uso das mesmas sem a criação de uma função UDF.

As funções no SQL Server são uma ótima forma de encapsular e reaproveitar código, mas ao mesmo tempo, podem acabar comprometendo a performance de suas consultas. Neste caso, a solução que atua como um meio termo entre função nativa do SQL Server e função escalar T-SQL seria a função escalar do CLR, que possui uma performance muito superior à função T-SQL (na grande maioria dos casos) e próxima da função nativa e ao mesmo tempo, possibilita o reaproveitamento e encapsulamento de código.

Através desse post, eu espero ter mostrado pra vocês uma forma real de otimização de consultas SQL, sem precisar alterar 1 linha de código, sem precisar alterar nada na sua instância. Em muitos casos, os índices estão sendo utilizados da forma esperada, as estatísticas estão atualizadas, nenhum warning no plano de execução, mas ao utilizar uma função T-SQL, a performance da query acaba sendo ruim.

Neste caso, o uso de funções CLR podem representar uma grande melhoria na sua aplicação/rotina e ganhar preciosos segundos/ciclos de CPU no dia a dia. Com isso, foi possível reduzir várias e várias horas de processamento/CPU diariamente nas instâncias do meu trabalho, simplesmente substituindo funções T-SQL por funções CLR e isso pode ser um grande diferencial na vida do DBA.

Espero que vocês tenham gostado desse post.
Qualquer dúvidas ou críticas, deixem aqui nos comentários.

Abraço!