- Este tópico contém 9 respostas, 4 vozes e foi atualizado pela última vez 13 anos, 4 meses atrás por
rman.
-
AutorPosts
-
2 de outubro de 2012 às 12:49 am #104552
maxmcosta
ParticipantePessoal, talvez possam tirar uma pequena duvida.
Tabelas:
base 408 registros
lista1 70 mil registros
lista2 70 mil registrosTenho 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!2 de outubro de 2012 às 3:02 am #104553joseniz
ParticipanteAs 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 ?2 de outubro de 2012 às 4:33 pm #104555rman
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.
2 de outubro de 2012 às 8:03 pm #104556fsitja
ParticipanteO 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.
3 de outubro de 2012 às 7:29 pm #104564maxmcosta
ParticipanteMeu 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!
3 de outubro de 2012 às 9:12 pm #104565rman
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.
4 de outubro de 2012 às 12:07 am #104570maxmcosta
ParticipanteBom, 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");
}}
4 de outubro de 2012 às 3:48 pm #104576rman
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'
17 de outubro de 2012 às 5:34 pm #104648maxmcosta
ParticipanteSenhores, 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?
17 de outubro de 2012 às 5:49 pm #104650rman
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.
-
AutorPosts
- Você deve fazer login para responder a este tópico.