Estou trabalhando no SQL Server 2019 .
Tenho uma tabela dbo.AllDates onde tenho todas as datas de 1990 a 2050 . Eu tenho outra tabela dbo.ActualExchangeRates onde tenho taxas de câmbio reais para certas moedas nas datas em que a taxa de câmbio é encontrada em determinada fonte.
Estou tentando escrever uma consulta para obter todas as moedas para todas as datas entre 2010 e 2020 . Se a taxa for encontrada, escreva a taxa, caso contrário, escreva NULL .
Dado este cenário e dado o código abaixo, alguém pode me ajudar a entender por que a consulta SELECT não está gerando nenhum resultado ou até mesmo não consegue ver o plano de execução estimado?
CREATE TABLE dbo.AllDates(Date date)
CREATE TABLE dbo.ActualExchangeRates(Date date, Currency char(3), Rate real)
--Query 1: Not generating any results or estimated plan
SELECT d.Date, m.Currency, c.Rate
FROM dbo.AllDates d
INNER JOIN (
select
currency,
'20100101' as mindate,
'20201231' as maxdate
from dbo.ActualExchangeRates
group by currency
) as m on d.date between m.mindate and m.maxdate
LEFT JOIN dbo.ActualExchangeRates C ON C.Currency = m.Currency and c.Date = d.Date;
Recebo o seguinte erro após a execução da consulta por 9 minutos em tabelas vazias:
Msg 701, Level 17, State 123, Line 5
Não há memória de sistema insuficiente no pool de recursos 'padrão' para executar esta consulta.
Parece que depende da quantidade de memória disponível para o servidor SQL até atingir o erro. Para mim, parece um bug no mecanismo SQL, pois não há dados na tabela.
Agora, eu sei que a consulta acima pode ser escrita de várias maneiras diferentes e outras maneiras podem gerar resultados, mas minha pergunta é por que o SQL Server simplesmente desliga para sempre nessa consulta, mesmo que ambas as tabelas estejam vazias ?
Isso é certamente um bug.
Não posso lhe contar os detalhes minuciosos da natureza exata do bug, mas alguns detalhes estão abaixo.
Enquanto o plano de execução está sendo compilado, o criador de perfil de desempenho do Visual Studio mostra que o tempo de CPU para o thread é gasto da seguinte maneira.
Portanto, muito tempo de CPU estava sendo gasto em
... -> sqllang.dll!COptContext::NormalizeQuery -> ... sqllang.dll!COptContext::PexprTransformTopLevel -> sqllang.dll!CSubRuleImpliedPredInnerAndAllLeftJn::BuildSubstitutes -> sqllang.dll!OptimizerUtil::PexprCreateConjOrDisj
e em
... -> sqllang.dll!COptContext::NormalizeQuery -> ... sqllang.dll!COptContext::PexprTransformTopLevel -> sqllang.dll!COptExpr::DeriveGroupProperties
A pilha mostra que o problema está surgindo durante o estágio de normalização da consulta da compilação e parece estar associado a uma regra
RuleImpliedPredInnerAndAllLeftJn
.O problema realmente desaparece quando essa regra é desativada,
option(queryruleoff ImpliedPredInnerAndAllLeftJn)
mas essa não é uma boa solução para o problema (não documentada e pode afetar o desempenho, pois não envia mais o predicado implícito de[C].[Date]>='2010-01-01' AND [C].[Date]<='2020-12-31'
para a leitura dedbo.ActualExchangeRates C
)A adição
option(querytraceon 3604, querytraceon 2373)
mostra que a compilação parece ter entrado em algum tipo de círculo de derivação de propriedadesLogOp_LeftOuterJoin -> ScaOp_Comp -> ScaOp_Comp -> ScaOp_Logical -> ScaOp_Const -> ScaOp_Comp -> ScaOp_Const -> ScaOp_Comp -> ScaOp_Logical -> ScaOp_Logical -> LogOp_Select -> LogOp_LeftOuterJoin -> ...
com o uso de memória aumentando constantemente até que eventualmente ela fique sem memória e a tentativa de compilação termine. ( Amostra de saída mostrando alguns circuitos )Na minha máquina de desenvolvimento
de antes e depois cresce cerca de 390.000 a cada execução com falha.