Eu tenho um procedimento armazenado que une três tabelas grandes (cerca de 20 milhões de registros cada) e carrega registros em uma tabela temporária. Os dados na tabela temporária são então mesclados em uma tabela existente de cerca de 60 milhões de registros.
O servidor ficou offline com uma mensagem de erro de:
AppDomain 2 (SSISDB.dbo.[runtime].1] está marcado para descarregamento devido à pressão da memória.
Depois de colocar o servidor online novamente, reiniciei os serviços SQL para limpar todos os processos que podem estar demorando. Começou o trabalho novamente e foi concluído sem problemas.
Estou executando o SQL Server 2019 com 128 GB de RAM. A memória máxima do servidor é 117964 MB em um servidor virtual de 64 bits. Alguém me disse no Gerenciador de Tarefas que o uso de memória estava em 94% e esse poderia ser o problema. Mas o SQL não pega toda a memória disponível e a mantém? Então parece que está funcionando como pretendido.
sp_WhoIsActive
revelou algumas consultas com status 'Suspended' e 'Awaiting_Command', mas não acredito que tenham tido muito impacto. 128 GB de ram parecem adequados, mas acho que é relativo ao trabalho que está sendo solicitado a fazer. Alguma idéia de como solucionar problemas ou evitar que aconteça novamente?
A unidade de dados para o servidor é de cerca de 1,6 TB. Os dois bancos de dados maiores na junção são 10 GB com 19 milhões de linhas e 13 GB com 20 milhões de linhas. Esses vão para uma tabela temporária e depois MERGE
para uma tabela de 26 GB com 53 milhões de linhas.
A concessão de memória solicitada é de 45 GB e a real é de 30 GB. O trabalho foi executado fora do horário comercial regular, portanto, não deveria haver consultas concorrentes, mas não posso confirmar 100% que alguém não estava trabalhando até tarde.
Eu notei que ele está tendo que fazer um CONVERT_IMPLICIT
bem. Isso tem um impacto significativo na memória necessária?
Link para o plano de consulta: https://www.brentozar.com/pastetheplan/?id=SyXaty7xK
Sobre o seu servidor
Essa consulta se espalha mal em dois lugares, apesar de uma concessão de memória de 29 GB. Isso é o máximo do que uma consulta pode solicitar em seu sistema com a memória máxima do servidor configurada para 115 GB.
A causa para uma concessão de memória desse tamanho é o otimizador estimando que ele precisará classificar 46 GB de dados:
Você pode ver os detalhes da porcentagem de concessão de memória consultando o Resource Governor - uma única consulta pode solicitar aproximadamente 25% da configuração de memória máxima do servidor - e até três consultas podem solicitar a concessão total simultaneamente.
O fato de você obter uma concessão desse tamanho e ainda ver derramamentos dessa magnitude e consumo de tempo provavelmente significa que seu servidor está muito pouco provisionado no que diz respeito à memória.
Como ambos os operadores são executados no modo de lote, o tempo que você vê é por operador .
Tenho certeza de que, se você analisasse as estatísticas de espera para este servidor (dado os 1,6 TB de dados),
PAGEIOLATCH_
estaria lá em cima, juntamente com potencialmenteSLEEP_TASK
ouIO_COMPLETION
se derramamentos desse tamanho são comuns. Embora ambas as esperas também possam estar associadas a outras coisas, muitas vezes as vejo se acumularem em situações como a sua.Eu sugiro primeiro adicionar uma quantidade mais realista de memória ao seu servidor. Não sei qual é esse número (e não posso dizer isso aqui), mas provavelmente apontaria para 512 GB ou mais com base no tamanho dos dados e nada mais. Você também deve ativar as páginas de bloqueio na memória , se ainda não estiver.
Sobre sua consulta
Não consigo ver o texto completo, pois tudo o que aparece no plano de consulta é a inserção e parte da lista de seleção , mas, considerando o que parece, posso fazer algumas suposições razoáveis sobre a qualidade geral do código.
Por exemplo, várias das junções estão em expressões, o que provavelmente indica que você está envolvendo colunas de junção em funções como
rtrim
ouisnull
ou algo assim.Mas seu principal problema está no final da consulta e nos vazamentos mostrados acima.
Vamos falar sobre eles!
Junção de hash
O Hash Join está lá para o
DISTINCT
que você lançou em sua consulta de 143 colunas . Isso me dá arrepios, e quem escreveu isso deve considerar fortemente algum treinamento se quiser continuar trabalhando com o SQL Server.Eu recomendo encontrar uma combinação menor de colunas que produzam linhas exclusivas e usar row_number para marcá-las como mostro neste vídeo:
Um exemplo de pseudocódigo se parece com isso:
Apenas certifique-se de que seus índices sejam apropriados para suportar a função de janelas.
Ordenar
A classificação está lá porque sua
#temp
tabela possui um índice clusterizado.Se você criar a tabela como um heap e adicionar o índice posteriormente, poderá evitar esse desconforto quando a consulta for executada, embora adicionar o índice possa não ser divertido dependendo de vários fatores locais.
Eu também sugiro adicionar uma
tablock
dica à sua inserção para incentivar uma inserção totalmente paralela, se possível.No momento, sua consulta tem um único encadeamento antes da inserção, o que certamente pode prejudicar o desempenho nessa contagem de linhas.
Dado o estado geral da consulta, pode valer a pena explorar reescritas para dividir a consulta em partes menores que identificam o conjunto exclusivo de chaves em que você está interessado e, em seguida, obter o conjunto completo de colunas em que você está interessado: