none
[RESOLVIDO] Data mais próxima de uma data informada RRS feed

  • Pergunta

  • Boa tarde senhores,

    Implementei o código abaixo e gostaria de saber se é a melhor forma de se forma, pois está demorando muito. Estou usando linq sql para buscar as informações.

    public MedicaoDado retornaMedicoesPorDataProxima(int codigo, DateTime dataInformada)
            {
                MedicaoDado medicaoResult = new MedicaoDado();
    
                var medicaoAnterior = (from m in entities.MedicaoDado
                              where m.med_res_id == codigo
                              && m.med_data_medicao <= dataInformada
                              orderby m.med_data_medicao descending
                              select m).FirstOrDefault();
    
                var medicaoPosterior = (from m in entities.MedicaoDado
                              where m.med_res_id == codigo
                              && m.med_data_medicao >= dataInformada
                              orderby m.med_data_medicao ascending
                              select m).FirstOrDefault();
                
                //Se nenhuma das duas data NÃO forem null, é feita a verificação para saber quem é a mais próxima da data informada
                if (medicaoAnterior != null && medicaoPosterior != null)
                {
                    int diferencaDtAnterior = Math.Abs(((TimeSpan)(medicaoAnterior.med_data_medicao - dataInformada)).Days);
                    int diferencaDtPosterior = Math.Abs(((TimeSpan)(medicaoPosterior.med_data_medicao - dataInformada)).Days);
    
                    if (diferencaDtAnterior <= diferencaDtPosterior)
                    {
                        medicaoResult = medicaoAnterior;
                    }
                    else
                    {
                        medicaoResult = medicaoPosterior;
                    }
                }
                else
                {
                    //Se nenhuma das duas data FOREM null, é feita a verificação para saber quem é a mais próxima da data informada
                    if (medicaoAnterior == null && medicaoPosterior == null)
                    {
                        //Não possui dados
                    }
                    else
                    {
                        //Se a data posterior a data informada for null, pega-se a data anterior a data informada
                        if (medicaoPosterior == null)
                        {
                            medicaoResult = medicaoAnterior;
                        }
                        //Se a data anterior a data informada for null, pega-se a data posterior a data informada
                        else
                        {
                            medicaoResult = medicaoPosterior;
                        }
                    }                
                }
    
                return medicaoResult;
            }

     


    segunda-feira, 23 de dezembro de 2013 17:25

Respostas

  • Deleted
    segunda-feira, 23 de dezembro de 2013 22:23
  • Rafael,

        Este é um fórum dedicado a tirar dúvidas de SQL Server. Fiz algumas modificações nas suas queries para adequá-las à sintaxe do SQL Server e gostaria que todos os testes fossem feitos com base nelas. Se houver qualquer outro problema e que porventura possa estar relacionado a LinQ, EF ou acesso à dados, solicito que você poste no fórum de LinQ.

    select max(med_data_medicao) from MedicaoDado where med_res_id = Código and med_data_medicao <= DataInformada
    
    select min(med_data_medicao) from MedicaoDado where med_res_id = Código and med_data_medicao >= DataInformada
    

       Agora, as perguntas que o José.Diz lhe fez:

       - há índice cuja primeira (ou única) coluna seja a coluna med_data_medicao?
      - há índice cuja primeira (ou única) coluna seja a coluna med_res_id?

       Eu acrescento:

       - Você já verificou o plano de execução da sua query no SQL Server?

       - Existe um índice com os campos med_res_id e med_data_medicao?

        Para verificar quais índices existem na sua tabela, faça o seguinte:

        Abra o SSMS, clique em New Query, escreva:

        USE NomedaSuaBase
    
        GO
    
        -- Clique em <F5>
    
        -- escreva o nome da sua tabela:
    
        MedicaoDado
    

        Marque o nome todo da sua tabela com o mouse e clique em <ALT><F1>. Vai aparecer diversas informações sobre a sua tabela, um dos resultados que surgirá inicia com "index name" e terá na coluna "index Keys" os campos que fazem parte deste índice. Verifique se há um índice com as colunas citadas.


    Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008

    • Sugerido como Resposta Edinaldo Junior quinta-feira, 26 de dezembro de 2013 17:55
    • Marcado como Resposta Rafael Rodriguess quinta-feira, 26 de dezembro de 2013 18:16
    quinta-feira, 26 de dezembro de 2013 15:10
    Moderador
  • Rafael,

        Em poucas palavras, o índice faz exatamente o que um índice faz em um livro. Quando você quer determinado assunto, vai até o índice e ele indica em qual página do livro está a sua informação.

        Entretanto, estaríamos saindo fora do tema da sua thread. Se você deseja mais informações, abra uma nova pergunta no fórum. 

        Eu sugiro a você que procure no site da Microsoft sobre a iniciativa MVA, que são treinamentos gratuitos de diversas ferramentas. SEgue o link do MVA de SQL Server: http://www.microsoftvirtualacademy.com/product-training/product-sql-server-pt#?fbid=KUWXv_zdYPN


    Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008

    quinta-feira, 26 de dezembro de 2013 18:13
    Moderador

Todas as Respostas

  • A tabela MedicaoDado retorna as seguintes colunas:

    med_id
    med_cota 
    med_volume 
    med_data_medicao 
    med_data_insercao
    med_res_id 

     


    segunda-feira, 23 de dezembro de 2013 19:09
  • A tabela atualmente tem quase 114 mil registros e está demorando em média 50 segundos para fazer as comparações de data. Desculpe a ignorância amigo, mas não entendi o que quis dizer com índices das colunas med_data_medicao e med_res_id.

    Não sei se isso pode auxiliar em alguma coisa, mas o método que chama retornaMedicoesPorDataProxima é:

    public void BuscaMedicoes()
            {            
                List<Reservatorio> reservatorios = new List<Reservatorio>();
    List<MedicaoDado> medicoes = new List<MedicaoDado>();
    
                                reservatorios.AddRange(reservatorioRepositorio.buscarTodosReservatorios());
               
                    
                    foreach (var r in reservatorios)
                    {
                        //Agora é buscar as medições de cada reservatório que se aproxima da data informada
                        medicao = medicaoRepositorio.retornaMedicoesPorDataProxima(r.res_id, data);
                        if (medicao.med_id != 0)
                        {
                            medicoes.Add(medicao);
                        }
    
                    }
               
            }


    terça-feira, 24 de dezembro de 2013 11:36
  • Se ta fazendo com Linq to SQL Classes ou Entity Framework ?

    Outra coisa ... a Lentidão está no processo está na quantidade de registros + BuscaMedicoes(), esse código precisa ser refatorado.

    Se eu tivesse essa tabela eu poderia testá-la pra você e os indices que o nosso amigo disse é de extrema importância para aumentar a performace desses leitura desses registros ... 

    Se pude dispor a tabela e podendo ser dados fictícios a gente pode testar!

    Me fala a camada que utiliza e a regra de negócio! +  SQL Create Table da tabela + dados fictícios ...


    Fulvio Cezar Canducci Dias

    terça-feira, 24 de dezembro de 2013 13:34
  • Rafael,

        Este é um fórum dedicado a tirar dúvidas de SQL Server. Fiz algumas modificações nas suas queries para adequá-las à sintaxe do SQL Server e gostaria que todos os testes fossem feitos com base nelas. Se houver qualquer outro problema e que porventura possa estar relacionado a LinQ, EF ou acesso à dados, solicito que você poste no fórum de LinQ.

    select max(med_data_medicao) from MedicaoDado where med_res_id = Código and med_data_medicao <= DataInformada
    
    select min(med_data_medicao) from MedicaoDado where med_res_id = Código and med_data_medicao >= DataInformada
    

       Agora, as perguntas que o José.Diz lhe fez:

       - há índice cuja primeira (ou única) coluna seja a coluna med_data_medicao?
      - há índice cuja primeira (ou única) coluna seja a coluna med_res_id?

       Eu acrescento:

       - Você já verificou o plano de execução da sua query no SQL Server?

       - Existe um índice com os campos med_res_id e med_data_medicao?

        Para verificar quais índices existem na sua tabela, faça o seguinte:

        Abra o SSMS, clique em New Query, escreva:

        USE NomedaSuaBase
    
        GO
    
        -- Clique em <F5>
    
        -- escreva o nome da sua tabela:
    
        MedicaoDado
    

        Marque o nome todo da sua tabela com o mouse e clique em <ALT><F1>. Vai aparecer diversas informações sobre a sua tabela, um dos resultados que surgirá inicia com "index name" e terá na coluna "index Keys" os campos que fazem parte deste índice. Verifique se há um índice com as colunas citadas.


    Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008

    • Sugerido como Resposta Edinaldo Junior quinta-feira, 26 de dezembro de 2013 17:55
    • Marcado como Resposta Rafael Rodriguess quinta-feira, 26 de dezembro de 2013 18:16
    quinta-feira, 26 de dezembro de 2013 15:10
    Moderador
  • Realmente fiz a verificação amigo e não existe índice com os campos med_res_id e med_data_medicao. 

    A tabela já possui um indice clusterizado que é o indice da tabela med_id.

    Como ficaria com a criação desses índices?



    quinta-feira, 26 de dezembro de 2013 17:26
  • Incrível!

    Apenas criei os índices para as colunas que vocês me sugeriram e reduzi o tempo de pesquisa de 50 segundos para 15 segundos. 

    Agora alguém poderia me dar uma explicação na prática o que acontece para que a pesquisa fique otimizada dessa forma?

    quinta-feira, 26 de dezembro de 2013 17:54
  • Rafael,

        Em poucas palavras, o índice faz exatamente o que um índice faz em um livro. Quando você quer determinado assunto, vai até o índice e ele indica em qual página do livro está a sua informação.

        Entretanto, estaríamos saindo fora do tema da sua thread. Se você deseja mais informações, abra uma nova pergunta no fórum. 

        Eu sugiro a você que procure no site da Microsoft sobre a iniciativa MVA, que são treinamentos gratuitos de diversas ferramentas. SEgue o link do MVA de SQL Server: http://www.microsoftvirtualacademy.com/product-training/product-sql-server-pt#?fbid=KUWXv_zdYPN


    Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008

    quinta-feira, 26 de dezembro de 2013 18:13
    Moderador
  • Amigo, irei fazer as mudanças que me sugeriu, mas estava fazendo uns testes aqui e exclui os índices e depois inseri eles novamente e a consulta voltou e demorar. Está demorando uns 30 segundos agora! O que será que aconteceu?
    sexta-feira, 27 de dezembro de 2013 13:08
  • Amigo,

    Fiz uns testes e pesquisas aqui e a melhor solução é utilizando o FirstOrDefault(), pois ele pega um único registro e se não houver nada ele traz vazio. Tentei utilizar o TAKE(1), que seria equivalente ao TOP 1, mas não é uma boa ideia, pois apesar de retornar um único registro ele vem em um IEnumerable<string>.  

    Ao invés de colocar um único índice com as duas colunas (med_res_id e med_data_medicao), coloquei um índice para e minha consulta que estava com 15 segundos (que já estava boa!!!) foi para 6 segundos (que agora está fantástico!!!). 

    No geral o resultado foi excelente! Eu estava com uma pesquisa que demorava 50 segundos que foi reduzida para 6 segundos.

    Se ninguém tiver mais nada que acrescentar finalizarei a Thread.

    Obrigado a todos que me ajudaram!!!!!!!!


    sexta-feira, 27 de dezembro de 2013 18:07