Pular para o conteúdo
Visualizando 10 posts - 1 até 10 (de 10 do total)
  • Autor
    Posts
  • #104552
    maxmcosta
    Participante

      Pessoal, talvez possam tirar uma pequena duvida.

      Tabelas:
      base 408 registros
      lista1 70 mil registros
      lista2 70 mil registros

      Tenho Oracle 10G express edition instalado no windows server 2003, rodando sobre o hardware i72600, 4 núcleos e simulando mais 4, 2GB de memória.

      Meu sistema faz um loop na tabela “base”, para cada registro são feitas duas consultas em mais duas tabelas, ambas as tabelas consultadas tem cerca de 70 mil registros. Explicando melhor, no loop, para cada registro da tabela “base com 408 registros” é realizado o select abaixo:


      //Primeira consulta
      select valor from lista1 WHERE ID_lista = "+idListaAtual+" and ID_base_lot = "+id_lot+" and PERIODO BETWEEN ? AND ?"
      - Se encontrar algum valor armazeno em uma variável;

      //segunda cosulta
      select valor from lista2 WHERE ID_lista = "+idListaAtual+" and ID_base_lot = "+id_lot+" and PERIODO BETWEEN ? AND ?"
      - Se encontrar algum valor armazeno em uma variável;

      Ocorre que esse loop leva cerca de 35 segundos para ser executada por completo.
      Observei o consumo de processador da maquina onde está instalado o Oracle e não passa de 20%.

      Alguém saberia me dizer como otimizar essa consulta? Como aproveitar melhor o processador?
      Grato!

      #104553
      joseniz
      Participante

        As informações que você passou são insuficientes. Seu problema parece ser I&O e não processador.

        Qual o tamanho da SGA ?
        Qual o relacionamento entre essas tabelas ?
        Quais os índices criados ?
        As estatísticas de ambas estão atualizadas ?

        #104555
        rman
        Participante

          @maxmcosta

          Ao invés de fazer um SELECT na tabela pai e fazer mais 2 SELECTs nas tabelas filhas, você pode fazer apenas 1 SELECT com 2 LEFT JOIN.

          #104556
          fsitja
          Participante

            O problema é que está sendo feito 408 mil Selects vezes 2… quando poderia um único SQL resolver através de um Join.

            O uso de CPU e de I/O é baixo pois o banco está perdendo tempo em espera, aguardando chaveamentos de contexto entre o PL/SQL enviar o comando para o engine de SQL milhares e milhares de vezes. Mesmo que cada “troca” de bastão dessas demore muito pouco (< 1 ms por exemplo), lembre-se que você está fazendo isso 816 mil vezes e esse probleminha vira um problemão pois não há escalabilidade.

            Resumindo, faça num SQL só a lógica, que é o forte do Oracle.

            #104564
            maxmcosta
            Participante

              Meu conhecimento em SQL não é muito.

              Poderiam me ajudar a criar esse select que substituiria os dois mostrados na mensagem acima?

              Tentei fazer da forma abaixo, não deu erro, mas também não retornou nenhuma informação:

              SELECT valor as lista1, valor as lista2
              FROM lista1, lista2
              LEFT JOIN lista1 on (lista1.ID_lista = '2170' and lista1.ID_base_lot = '31' and lista1.PERIODO BETWEEN '01/06/12' AND '01/06/12')
              LEFT JOIN lista2 on (lista2.ID_lista = '2170' and lista2.ID_base_lot = '31' and lista2.PERIODO BETWEEN '01/06/12' AND '01/06/12');

              Grato pelas dicas!

              #104565
              rman
              Participante

                @maxmcosta

                A tabela base é a tabela que vai no FROM, e as tabelas lista1 e lista2 fazem o LEFT JOIN.

                Posta os 3 SELECT que você tem hoje.

                #104570
                maxmcosta
                Participante

                  Bom, não sei se seria o correto, mas fiz dessa forma:

                  SELECT lista1.valor as v1, lista2.valor as v2 from lista1, lista2
                  where
                  (
                  lista1.ID_lista = '2170' and lista1.ID_base_lost = '31' and lista1.PERIODO BETWEEN '01/06/12' AND '01/06/12' and
                  lista2.ID_lista = '2170' and lista2.ID_base_lost = '31' and lista2.PERIODO BETWEEN '01/06/12' AND '01/06/12'
                  )

                  Agora a consulta que demorava 35 segundo está sendo realizada com 3 segundos.

                  A ideia de usar o join funcionaria apenas no caso de filtrar as três tabelas ao mesmo tempo? Vou postar abaixo de forma resumida como está o código do loop, assim se alguém tiver alguma ideia para melhorar ainda mais agradeço…


                  psBase = conn.prepareCall("select id, descricao from base where subgrupo = '1.0' or subgrupo = '2.0' or subgrupo = '3.0'");
                  rsBase = psBase.executeQuery();

                  //loop na tabela base
                  while(rsBase.next()){

                  Int idListaAtual = rsBase.getString("id");

                  //aki dentro executo os dois selects, no caso atual, já substitui os dois select por um só, como informado acima...

                  psRealizado = conn.prepareCall("SELECT lista1.valor as v1, lista2.valor as v2 from lista1, lista2 where
                  (
                  lista1.ID_lista = "+idListaAtual+" and lista1.ID_base_lost = "+id_base_lost+" and lista1.PERIODO BETWEEN '01/06/12' AND '01/06/12' and
                  lista2.ID_lista = "+idListaAtual+" and lista2.ID_base_lost = "+id_base_lost+" and lista2.PERIODO BETWEEN '01/06/12' AND '01/06/12'
                  )");

                  rsRealizado = psRealizado.executeQuery();

                  //Se acho algo mando para arrais...

                  if (rsRealizado.next()){
                  lista1[contArray] = rsRealizado.getFloat("v1");
                  lista2[contArray] = rsRealizado.getFloat("v2");
                  }

                  }

                  #104576
                  rman
                  Participante

                    @maxmcosta

                    A ideia é remover o loop, fazendo apenas 1 consulta:


                    SELECT B.ID,B.DESCRICAO,L1.VALOR V1,L2.VALOR v2
                    FROM BASE B
                    LEFT JOIN LISTA1 L1 ON L1.ID_LISTA = B.ID AND L1.ID_BASE_LOT = 1 AND L1.PERIODO BETWEEN '01/06/12' AND '01/06/12'
                    LEFT JOIN LISTA2 L2 ON L2.ID_LISTA = B.ID AND L2.ID_BASE_LOT = 1 AND L2.PERIODO BETWEEN '01/06/12' AND '01/06/12'
                    WHERE B.SUBGRUPO = '1.0' OR B.SUBGRUPO = '2.0' OR B.SUBGRUPO = '3.0'

                    #104648
                    maxmcosta
                    Participante

                      Senhores, muito obrigado pela ajuda até o momento…

                      Não consegui entender uma coisa, se eu fizer o select da forma explicada pelo rman, removendo o loop, como vou passar o “valor” de cada registro da tabela base encontrados nas lista 1 e 2 para os arrays lista 1 e 2?

                      Neste caso eu preciso do loop?

                      #104650
                      rman
                      Participante

                        @maxmcosta

                        Sim, para passar os valores para o array é necessário do loop mesmo. No SELECT adicione para retornar a PK da tabela LISTA1 e LISTA2, compare se a PK não for NULO, se não for adicione o valor para a LISTA correspondente.

                      Visualizando 10 posts - 1 até 10 (de 10 do total)
                      • Você deve fazer login para responder a este tópico.