Memória usada não liberada após uma exportação SQL BULK Insert / BCP

10

Eu criei uma tabela SQL muito básica da seguinte maneira

CREATE TABLE [dbo].[TickData](
[Date] [varchar](12) NULL,
[Time] [varchar](12) NOT NULL,
[Symbol] [varchar](12) NOT NULL,
[Side] [varchar](2) NOT NULL,
[Depth] [varchar](2) NOT NULL,
[Quote] [varchar](12) NOT NULL,
[Size] [varchar](18) NOT NULL
    ) ON [PRIMARY]

Em seguida, realizei uma inserção em massa de 3 GB

    BULK
    INSERT TickData
    FROM 
    'C:\SUMO.csv'
    GO

Em seguida, o uso da RAM para o servidor SQL disparou, consumindo ~ 30Go de RAM:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Prefiro pensar que este é um comportamento anormal e que medidas podem ser tomadas para evitar isso.

EDIT:
Ok, este parece ser o comportamento padrão. Justo.
No entanto, por que a memória não é liberada muito tempo após o término da inserção em massa?

Algumas considerações extras:
Como nos comentários sobre o SQL Server que libera a memória quando o sistema operacional recebe instruções, minha experiência prática em um servidor Xeon de 24 Gb e 32 Gb prova que isso é inexato: Depois que uma extração de BCP com memória voraz termina Eu tenho um pool de instâncias .net do meu aplicativo de processamento de dados que precisam processar os dados extraídos e eles ficam sufocados / lutando para compartilhar a memória restante para tentar executar seus trabalhos, o que leva muito mais tempo que quando o SQL Server é ativado desligado e a memória está disponível para todos os aplicativos para compartilhar. Eu tenho que parar o SQL Server Agent para que tudo corra bem e impedir que os aplicativos falhem no Articiallt causado pela exceção OutOfMemmroy. Quanto ao limite / limitação artificial da memória brutal, se houver memória livre disponível, por que não usá-lo? Idealmente, preferiria ser definido dinamicamente para se adaptar ao que está disponível, em vez de apenas ser limitado à força "aleatoriamente". Mas eu acho que isso é por projeto, então caso encerrado neste último ponto.

Mehdi LAMRANI
fonte
6
Por que o SQL Server deve liberar a memória? Se for necessário que a memória faça essa operação uma vez, será necessário novamente. Se o SQL Server liberasse a memória, para que você a usaria? Por que a memória precisa estar livre? Se você usar a memória para outra coisa, essa inserção em massa será executada novamente, o que deve acontecer?
Aaron Bertrand
A única ação que você pode executar para evitar isso é definir o tamanho máximo da memória. Para "recuperar" a memória, você pode reiniciar o serviço SQL Server. Obviamente, isso liberará a memória e, quando o serviço reiniciar, alocará a memória normalmente.
TMN
Limpei a última edição. Se você deseja discutir / discutir os méritos ou questões de como o SQL Server (ou qualquer outro mecanismo de banco de dados) é codificado, encontre um lugar melhor para fazê-lo. A pergunta original foi respondida, aparentemente correta e suficientemente. Se este Q continuar rastejando, ele pode ficar bloqueado.
23412 JNK
Não há nada de errado em querer saber respostas e discutir metodologias, apenas não aqui em um site de perguntas e respostas. Você pode definitivamente ter essa discussão no chat ou em um fórum em algum lugar, mas o Stack Exchange é um pouco mais estruturado e as perguntas para discussão serão encerradas muito rapidamente.
23412 JNK
3
Além disso, como um moderador não, eu estou querendo saber por que você está executando coisas não SQL no seu servidor? A caixa deve ser reservada APENAS para o SQL Server, é como o DBA 101. O mecanismo não foi projetado para um ambiente de recursos compartilhados.
23412 JNK

Respostas:

12

É um comportamento normal do SQL Server alocar o máximo de memória possível para seu buffer pool. Bancos de dados funcionam melhor com muito buffer. Se você deseja alterar o comportamento, pode definir a configuração 'max server memory' . Alguma boa leitura de fundo sobre isso está aqui.

Matt Whitfield
fonte
11
No que diz respeito à sua edição, o comentário de Aaron é bom. O motivo é que há pouco sentido em um servidor de banco de dados liberando memória. O SQL Server responderá à pressão da memória e liberará memória, se for necessário, mas isso realmente não deve ser necessário.
Matt Whitfield
@MikaJacobi Desculpe, mas sua segunda edição está errada. Do ponto de vista do desenvolvedor, entendo seu ponto de vista, mas há uma diferença entre a criação de vários aplicativos que coexistem e um serviço de servidor que realmente deve ser o único serviço que consome memória na máquina. Se você deseja que o SQL Server se comporte como um aplicativo "normal", defina a memória máxima e vá embora. Sua pergunta foi por que funciona dessa maneira e isso foi respondido. Se sua pergunta agora é "bem, eu não gosto que funcione dessa maneira" - desculpe, mas isso não é mais uma pergunta.
Aaron Bertrand
Justo. Meu ponto de vista é que deveria haver uma opção para ativar ou desativar isso, e a suposição de que o SQL server é o único Aplicativo em um Servidor é realmente abusiva (pode ser verdade para grandes empresas com grandes redes, mas essa não é a única). possível nem a configuração mais comum)
Mehdi Lamrani
Ainda não entendo por que você precisa do SQL Server para liberar a memória. Se outros aplicativos precisarem, eles o recuperam do SQL Server e o SQL Server obedece. Até que esses outros aplicativos precisem, qual é a finalidade da liberação da memória?
Aaron Bertrand
11
@AaronBertrand Ok, posso estar errado, mas como afirmado na minha nova edição anterior, não foi isso que testemunhei: a memória não foi liberada quando outro aplicativo precisou muito, causando falhas de memória (daí a minha insatisfação ...) De qualquer forma, vamos Para encerrar o assunto, acho que não há necessidade real de discutir mais do que isso.
Mehdi LAMRANI
7

Se você realmente deseja que o sistema operacional retire a memória do SQL Server, pegue um grande arquivo de 20 GB e copie-o pela rede. O SQL Server liberará a memória conforme o sistema operacional precisar. Mas eu observaria uma variedade de contadores de desempenho enquanto isso acontecia e veria como o desempenho do seu BULK INSERT muda se você executá-lo novamente enquanto a cópia está em andamento ou imediatamente após.

Se você quiser fazer isso manualmente, defina um limite inferior na configuração de memória máxima do servidor do SQL Server e reinicie o serviço. Agora, o SQL Server não usará 28 GB, mesmo que seja necessário. Mas isso parece limitar artificialmente o SQL Server.

O que você espera é um comportamento mais flexível, onde você pode ter memória livre parte do tempo. Para qual propósito? É como diminuir um arquivo de banco de dados para liberar espaço em disco que você não pode usar para outros fins, porque o arquivo de banco de dados crescerá novamente?

É engraçado, se você digitar uma pesquisa no Google por "por que o SQL Server não", o preenchimento automático mais comum é "liberar memória".

Aaron Bertrand
fonte
"O que você parece esperar é um comportamento mais flexível." Exatamente. Eu quero que o SQL server use toda a memória disponível quando estiver disponível, mas quando esses momentos difíceis terminarem, volte ao estado "sleep" e deixe os outros aplicativos que precisam de memória fazer seu trabalho confortavelmente (você pode dar uma olhada no meu nova última edição sobre este ponto)
Mehdi LAMRANI 23/07
Para um caso concreto que ilustra por que eu preciso fazer isso, você pode dar uma olhada @ meu último comentário para JNK na parte inferior da questão
Mehdi Lamrani
4

Infelizmente, isso é por design; consulte esta postagem. No entanto, neste post, ele fornece algumas instruções sobre como controlá-lo.

/server/251832/sql-server-bulk-insert-physical-memory-issue

Alocação de Memória

A memória não está freedativa porque aloca muito a memória como um aplicativo .NET. Como a alocação de memória é cara, ela será mantida, a menos que o SO solicite. Mas, não tema, se o sistema operacional desejar a memória, ela será obtida, exatamente como em um aplicativo .NET.

Mike Perrenoud
fonte
@MikaJacobi Claro, não há problema. Outra coisa a ser observada: para que você saiba, o SQL Server também controlará todos os núcleos, para limitar o número de núcleos disponíveis. Eu já vi o SQL Server destruir o sistema operacional em que ele é executado antes e tive que reiniciar o SQL Server em um data center.
Bom saber. Eu tenho 24 núcleos, então tudo bem por enquanto. Mas por que a memória não é liberada após o término da inserção em massa?
Desde que a inserção em massa tenha sido concluída, se o sistema operacional precisar da memória, ela será atribuída a ele, mas alocará a memória como um aplicativo .NET, de modo que, se precisar e mais ninguém precisar, poderá acessá-lo mais rapidamente.
Minha experiência de iniciação contradiz isso (veja a última edição).
Mehdi LAMRANI