Eu estava otimizando um procedimento armazenado escrito em cursores (DECLARE cur_name CURSOR...
O cliente viu que esse SP funcionou por mais de um dia, então meu gerente designou isso para mim.
Ao pesquisar, usei a variável de tabela e um loop while para iterar cada registro.
Para minha surpresa, a diferença entre os dois era enorme.
Alguém me disse que loop while é essencialmente um CURSOR.
Mas quando usei a variável de tabela com um WHILE LOOP, funcionou muito, muito rápido.
Agora, o que os cursores fazem internamente?
Os cursores são loops, mas podem ser mais complexos para o mecanismo de banco de dados implementar, dependendo das opções escolhidas.
Existem muitas opções para cursores no TSQL que podem ter um impacto significativo no desempenho, dependendo do
SELECT
que alimenta o cursor com informações (consulte a documentação do TSQL para obter detalhes ). As opções irão alterar quais bloqueios e outros recursos são necessários, podem fazer com que partes da consulta sejam executadas novamente e assim por diante. Além disso, seu loop interno pode estar fazendo coisas que afetam o comportamento do cursor, atualizando as tabelas base que ele lê de uma maneira que faz com que o mecanismo de banco de dados precise fazer mais trabalho.Se pudéssemos ver os dois bits de código de que você está falando, poderíamos ser mais específicos.
Ao executar a consulta inicial em uma variável de tabela e fazer um loop, você está essencialmente emulando um
STATIC FAST_FORWARD READ_ONLY
cursor, essas opções removem uma grande parte da complexidade com a qual o mecanismo poderia se preocupar. Seu principalSELECT
é definitivamente executado uma vez e de uma só vez, e seu loop não está competindo com outra atividade nos dados básicos enquanto interage com a cópia na variável.É claro que você também pode descobrir que algo dentro de seus dois loops (o que usa o cursor e o que não tem) tem métricas de desempenho significativamente diferentes se não forem escritas exatamente da mesma forma.
Sua solução, embora seja um
WHILE
loop, ainda é essencialmente um cursor no sentido de que você faz um loop sobre vários registros e executa uma ou mais instruções uma vez para cada registro. Não é oWHILE
loop em si, mas sim o padrão de codificação em que você faz um loop sobre as linhas de uma tabela e executa uma instrução para cada linha. Normalmente, as linguagens de programação "tradicionais" são baseadas em linhas - esta é a principal diferença entre SQL e, por exemplo, C#, VBA, etc.Por que sua consulta tem melhor desempenho com variáveis de tabela pode depender de vários fatores potenciais que não podemos deduzir de sua pergunta.
O que você deseja fazer ao eliminar soluções baseadas em cursores é transformá-las em soluções baseadas em conjuntos . Aqui está um pseudo-exemplo muito primitivo:
.. é equivalente à seguinte consulta baseada em conjunto:
Na primeira consulta, percorremos uma tabela, linha por linha. Na segunda consulta, todo o cálculo é feito com toda a tabela como um único "conjunto", ou seja, baseado em conjunto. Obviamente, a maioria dos padrões baseados em cursor será muito mais complexa, especialmente se eles iniciarem um procedimento armazenado para cada linha no cursor. Não há um único truque para converter uma solução baseada em cursor em uma baseada em conjunto.