Casos do dia a dia – uma query real que saiu de 9 horas para 47 segundos
No caso de hoje vamos falar sobre um caso que atuamos num cliente que tinha um job que chamava uma SP e o tempo médio de execução era de 9h30min.
Dentro dessa SP executava basicamente uma query como a abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
SELECT CTE.CAMPO1 ,CTE.CAMPO2 ,CTE.CAMPO3 ,CTE.CAMPO4 ,CTE.CAMPO2 - ABS(CTE.CAMPO3 + CTE.CAMPO4) CAMPO5 FROM ( SELECT dbo.FNCDATA(TAB1.CAMPO1) CAMPO1 ,TAB1.CAMPO2 ,TAB2.CAMPO3 ,TAB2.CAMPO4 FROM LS_SERVIDOR.BASE1.dbo.TABELA1 TAB1(NOLOCK) INNER JOIN LS_SERVIDOR.BASE2.dbo.TABELA2 TAB2 (NOLOCK) ON TAB1.CODIGO = TAB2.CODIGO WHERE TAB1.CAMPO1 >= @DT_INI ) CTE GROUP BY CTE.CAMPO1 ,CTE.CAMPO2 ,CTE.CAMPO3 ,CTE.CAMPO4 HAVING CTE.CAMPO2 - ABS(CTE.CAMPO3 + CTE.CAMPO4) <> 0 |
Era uma subquery que ia via linked server buscar os dados para serem agrupados e depois retornados. Essa subquery retornava mais ou menos 500k linhas via linked server. Enquanto o group by retornava menos de 10 linhas. Além dessa quantidade de dados sendo trafegados via linkedserver era utilizado uma função scalar na subquery que formatava um campo para data.
A solução para esse caso foi reescrever a query, onde ao invés de executar a query via linked server eu o faço via openquery, que irá abrir uma conexão e executar a query toda no servidor destino e trafegar os dados após o group by, fazendo assim com que muito menos dados fossem trafegados, pois o retorno do group by será de menos de 10 linhas.
E a outra alteração foi usar a função apenas no select final, onde o resultado é muito menor devido ao group by.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
SELECT dbo.FNCDATA(RESULT.CAMPO1) CAMPO1 ,RESULT.CAMPO2 ,RESULT.CAMPO3 ,RESULT.CAMPO4 ,RESULT.CAMPO5 FROM OPENQUERY(LS_SERVIDOR,' SELECT CTE.CAMPO1 ,CTE.CAMPO2 ,CTE.CAMPO3 ,CTE.CAMPO4 ,CTE.CAMPO2 - ABS(CTE.CAMPO3 + CTE.CAMPO4) CAMPO5 FROM ( SELECT TAB1.CAMPO1 ,TAB1.CAMPO2 ,TAB2.CAMPO3 ,TAB2.CAMPO4 FROM BASE1.dbo.TABELA1 TAB1 (NOLOCK) INNER JOIN BASE2.dbo.TABELA2 TAB2 (NOLOCK) ON TAB1.CODIGO = TAB2.CODIGO ) CTE GROUP BY CTE.CAMPO1 ,CTE.CAMPO2 ,CTE.CAMPO3 ,CTE.CAMPO4 HAVING CTE.CAMPO2 - ABS(CTE.CAMPO3 + CTE.CAMPO4) <> 0)' ) RESULT |