none
SQL SERVER com consumo excessivo de memória RRS feed

  • Pergunta

  • Boa tarde,

    Estou com um problema numa aplicação windows service que utiliza EF6.

    Esta aplicação processa uma massa de 2000 registros dentro de um intervalo de 1 hora esta com consumo crescente de memória (processo do SQL) a medida que executa as operações no banco de dados e nunca diminui.

    Em determinada ocasião, só o processo do SQL chegou a 6GB de memória e desligou o servidor.

    Esse servidor tem 8GB de memória.

    Para cada registro processado, a aplicação abre uma transação utilizando TransactionScope e faz conexões em três bancos de dados diferentes.

    Eu já verifiquei que todas as conexões (DbContext) estão sendo fechadas.

    Gostaria de saber o que poderia estar ocasionando esse consumo excessivo de memória e o que pode ser feito para diminui-lo.


    Otavio


    segunda-feira, 27 de julho de 2015 18:44

Todas as Respostas

  • Minha sugestão é você sempre chamar o Dispose ou colocar o contexto dentro de um using.

    using(Contexto contexto = new Contexto())

    {

    //Interação com banco de dados....

    }

    Também sugiro você desabilitar o LazyLoading, carregar entidades filhas por demanda.

      Configuration.LazyLoadingEnabled = false;

    Carregar por exemplo 

    var query = from u in contexto.Usuarios.Include(u=>u.Perfil) where u.Id == 1

    segunda-feira, 27 de julho de 2015 19:50
  • Olá, Otavio.
    Muitas coisas podem interferer na performance do seu banco/sistema. Fica difícil dar um diagnóstico sem olhar o código e o ambiente. Alguns pontos que eu olharia:

    1 - Como o EF está gerando suas queries.

    2 - Existem deadlocks entre as operações?

    3 - Quantas threads simultâneas estão em execução?

    4 - Qual a versão do Windows Server (aplicação e banco) e do MSDTC?

    5 - A aplicação está no mesmo servidor que o SQL?

    6 - Vc faz uso de queries dinâmicas ou tabelas temporárias no SQL?

    Sabe tirar dumps de memória?

    []s!


    MSc. Fernando Henrique Inocêncio Borba Ferreira
    Microsoft Development PFE
    Formed-Microsoft MVP - Visual C#/Data Platform Development
    http://ferhenriquef.com/ - http://twitter.com/ferhenriquef


    terça-feira, 28 de julho de 2015 01:31
    Moderador
  • Obrigado Cesar.

    Eu fiz a alteração em todos os contextos para desabilitar a propriedade Lazy Load.

    public VFBeneficiosEntities() : base("name=VFBeneficiosEntities")
    {
      this.Configuration.LazyLoadingEnabled = false;
    }

    No entanto ainda acho que esta consumindo bastante com 1 minuto de processamento já estava em 452944K.

    Não esta tão alto quanto antes, mas ainda assim esta sempre só aumentando.

    consumo de memoria

    Minhas conexões estão sendo finalizadas dentro da clausula finally (try catch) porque estou utilizando transação e utilizo o mesmo contexto para todas as operações.

    finally
    {
      if (dbCep.Database.Connection.State != ConnectionState.Closed)
        dbCep.Database.Connection.Close();
      dbCep.Dispose();
      dbCep = null;
      if (dbBeneficio.Database.Connection.State != ConnectionState.Closed)
        dbBeneficio.Database.Connection.Close();
      dbBeneficio.Dispose();
      dbBeneficio = null;
      if (dbObitos.Database.Connection.State != ConnectionState.Closed)
        dbObitos.Database.Connection.Close();
      dbObitos.Dispose();
      dbObitos = null;
    }
    //confirmar transação
    transacao.Complete();

    Estava verificando alguns pontos do código que poderiam ser melhorados para diminuir o consumo:

    Será que eu preciso matar os objetos que armazenam o resultado de uma consulta?

    por exemplo:

    var retorno = (from m in context.mailing_mapeamento 
    join c in context.mailing_campos on m.cod_campo_destino equals c.cod_campo where m.cod_mailing == codigoMailing select new { m.campo_origem, m.cod_campo_destino, campo_destino = c.nome_referencia, c.tabela_destino, c.tabela_referencia }).ToList();
    if(retorno != null)
    {
      ...
    }

    Se eu não finalizar esse objeto (null) os dados continuarao em memória ?

    Obrigado

    Otávio Camargo


    Otavio

    terça-feira, 28 de julho de 2015 01:55
  • Ola Fernando,

    Achei que o problema fosse realmente o Entity Framework.

    Eu olhei o SQL Profiler, e ele estava gerando muitas querys complexas.

    Resolvi retirar o EF e fazer as operações com conexão direta ao banco (SqlClient).

    Mas parece que ainda estou tendo problemas de performance.

    Este servidor é um Windows Server 2008 R2 com SP1, e SQL Server 2012.

    A aplicação roda no servidor de banco.

    Não estou usando queries dinamicas nem tabelas temporarias. A aplicação executa comandos texto, mas tem filtros  bem definidos).

    A aplicação não utiliza threads. Pega uma massa de 2000 registros de uma determinada tabela, e executa diversas consultas para colocar os dados em uma outra tabela. E finalizará quando os dados da tabela de origem se esgotar.


    Otavio

    quarta-feira, 5 de agosto de 2015 04:18
  • Olá, Otavio.

    Quanto tempo demora a execução de cada consulta?

    Já pensou em trabalhar com uma solução em massa ao invés de um-a-um?

    As tabelas envolvidas possuem índices?

    Os índices estão atualizados?

    Qual o volume de dados movido de um lado para o outro? Qual o tamanho da sua base?

    Nos logs do SQL existem registros de deadlocks?

    Vc tem usado TransactionScope ou DbTransaction?

    []s!


    MSc. Fernando Henrique Inocêncio Borba Ferreira
    Microsoft Development PFE
    Formed-Microsoft MVP - Visual C#/Data Platform Development
    http://ferhenriquef.com/ - http://twitter.com/ferhenriquef

    quarta-feira, 5 de agosto de 2015 12:49
    Moderador
  • Boa tarde,

    Não posso trabalhar com volume em massa porque existem processamentos (consulta a outras aplicações externas/manipulação de dados). 

    Essas tabelas são novas, tem pouca informação por enquanto, mas muito em breve terá mais de 10.000.000 de registro.

    Essas tabelas ainda não possuem índices definidos (exceto primary key) porque não sei ainda quais serão os campos mais utilizados nas consultas. Mas entendo que a ausência de índices não deveriam interferir na performance das operações de insert, já que os indices tornam as consultas mais rápidas e insert/update mais lenta, não é isso?

    A performance das operações esta boa. Processa 4 registros por segundo em média. Não há reclamação neste sentido. O problema é o consumo crescente de memória RAM. Pelo que pude observar, o SQL server não libera a memória depois que realizou as operações. Li alguns artigos que é possível limitar o consumo máximo de memória nas configurações do servidor (propriedades, opção "memória"). Mas não sei se esta é uma alternativa correta.

    O volume de dados tratado em cada execução do serviço em média é de 500.000. Mas em algumas ocasiões pode chegar a 2.000.000.

    Estou usando TransactionScope.


    Otavio

    quarta-feira, 5 de agosto de 2015 17:43
  • Onde encontro os logs de deadlock?

    Otavio

    quarta-feira, 5 de agosto de 2015 17:51
  • Otávio,

    Acredito que está dúvida deve ser levada para o forum de SQL. Lá, com especialistas em SQL, teremos uma resposta mais clara do que pode estar acontecendo.

    O que me deixa encucado é o volume de dados envolvido em cada transação. 500.000 me parece um número bastante alto de registros para cada transação. Não seria hora de analisar o relacionamento entre suas tabelas e adotar um melhor modelo para o seu sistema?

    Vc encontra os logs do SQL nesse caminho: C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPRESS\MSSQL\Log

     


    MSc. Fernando Henrique Inocêncio Borba Ferreira
    Microsoft Development PFE
    Formed-Microsoft MVP - Visual C#/Data Platform Development
    http://ferhenriquef.com/ - http://twitter.com/ferhenriquef

    quarta-feira, 5 de agosto de 2015 23:09
    Moderador
  • Ola Fernando,

    Obrigado pela ajuda.

    Verifiquei os logs e não há nenhum deadlock.

    Minha aplicação não manipula 500.000 registros por transação. 500.000 é o volume total de registros.

    O sistema estava programado para abrir e fechar uma transação para cada registro processado.

    Vi alguns relatos de que o controle de transação poderia ter influencia no consumo de memória, então retirei para poder verificar.

    De imediato houve um ganho inicial, já que diminuiu a velocidade no aumento consumo de memória, no entanto continua crescente. Nunca diminui.

    Vou levar este tópico para outro forum como me orientou.

    Obrigado

    Otavio Camargo


    Otavio

    sábado, 15 de agosto de 2015 12:33