Alexandre, seguem algumas obs gerais , vamos ver se te ajudo :

1) a regra de ouro para manipulações de dados, principalmente em
grandes volumes, cargas, etc, é SIMPLES : tente AO MÁXIMO fazer tudo
num único SQL, usando os recursos todos do SQL, apenas SE realmente
não conseguir aí sim tente um cursor PL/SQL, se ainda assim não
conseguir aí sim ir pra C ou java. Isso visando principalmente à
performance, já que (como já falado em msgs anteriores, blablabla) há
a questão de context switch, o CBO é *** COMPLETAMENTE *** incapaz de
otimizar SQLs separados (como o SELECT num cirsor e os SQLs dentro
dele), etc, etc, etc... No seu caso vc quer fazer um UPSERT (UPdate se
existe, inSERT se não), já existe ** SIM ** no 9i um comando SQL
nativo pra isso, é , como outros colegas já indicaram, o MERGE, 
consulte o manual "SQL Reference" do 9i que ele EXISTE SIM no 9i.
Obviamente, o MERGE trabalha com tabelas, então não sei se ficou claro
mas pra isso vc teria que usar o EXTERNAL TABLE, aí o teu
arquivo-texto funcionaria como se fosse uma tabela, podendo ser lida
via SELECT, participar de um MERGE, de um JOIN, normal....
 O problema pra isso na 9i é que lá vc não tem o recurso de DML Error
Logging 9que este sim só veio no 10g), então se o merge 9i em qualquer
linha falhar (veio um número errado no arquivo-texto, uma data, enfim,
qquer problema causador de exception) no 9i o merge falha
integralmente e vc não tem um log das falhas, só a mensagem de erro...
Outra coisa é que o MERGE *** exige *** constraint de PK/UK presente,
e ** proíbe ** UPDATEs na chave...
 Então a coisa é , SE isso é contornável/aceitável OK, vá de MERGE num
SQL só que deve ser mais performático, senão continue nas opções abaixo.

2) se vc não puder usar o MERGE por causa das limitações dele no 9i,
voltando um pouco a recomendação de usar SQLs para processar, outra
opção poderia ser (** sempre ** tendo o arquivo-texto como external
table) , E SE os INSERTs forem maioria esmagadora, fazer :

   a. inserir quem tá na tabela-external / arq.texto e não existe na
tab-destino com :

     INSERT /*+ APPEND */ INTO tabelasdestino (SELECT ... FROM
tabeladestino a, externalapontandoproarqtexto b
                                  WHERE a.chavedatabdestino      =
b.campodatabelaextorigem (+)
                                    AND b.campodatabelaextorigem is null);

   b. botar numa GTT para localizar rapidamente quem será UPDATE :

     INSERT /*+ APPEND */ INTO GTT (SELECT ... FROM tabeladestino a,
externalapontandoproarqtexto b
                                  WHERE a.chavedatabdestino      =
b.campodatabelaextorigem (+)
                                    AND b.campodatabelaextorigem is null);

   c. cursor (*** OBVIAMENTE *** com BULK COLLECT, FORALL, etc, etc)
lendo as linhas da GTT e fazendo os UPDATEs, com COMMIT só no final, etc.

3) já falamos algumas vezes, mas vale o reforço : ao usar o hint de
NOLOGGING num UPDATE sabe o que vc obtém ?? Pontas dos dedos mais
gastas do que o necessário, pois vc acabou de digitar algo IMPOSSÌVEL,
o banco só pode mesmo ignorar o que vc indicou... A questão é que o
NOLOGGING funciona introduzindo dados em blocos vazios, situados além
do limite dos blocos usados (daí o APPEND do hint), e *** OBVIAMENTE
*** um UPDATE vai mexer numa linha dum bloco que JÁ EXISTE, um bloco
potencialmente "cheio", já com outras linhas, NÂO TEM COMO fazer
append-mode com UPDATE por causa disso...

4) pro INSERT ... VALUES (valor1, valor2...) que vc usa vc não obterá
*** COISA ALGUMA ***, nada, niente, nill, null com o HINT de APPEND,
nem com as tabelas em modo de nolog : como já dito anteriormente, o
APPEND / NOLOG funciona se vc está inserindo múltiplas linhas, que
podem portanto ser dirigidas para blocos virgens/vazios acima da lista
de blocos usados - EVIDENTEMENTE um INSERT... VALUES está inserindo UM
REGISTRO APENAS, ele NÃO VAI movimentar múltiplos blocos (por
definição um registro SEMPRE está alocado prum bloco só, falando de
tabelas heap comuns), então não tem como se fazer APPEND-mode.... O
fato é, tanto pro teu UPDATE (por definição) quanto pro teu INSERT
(pois ele operam em uma linha só, ao invés de fazer INSERT ... (SELECT
multiplaslinhas) vale aí o bordão de um vilão da minha infância ;
ZEEEROOOO!!! Blz ?

5) finalmente, se por qquer motivo não der pra fazer nada do acima, ao
menos altere a sua rotina para NÂO ficar lendo e processamento uma
linha por vez do arquivo-texto (a external table seria ótima pra isso)
e processe com BULK COLLECT e FORALL o cursor resultante.

[]s

  Chiappa

--- Em oracle_br@yahoogrupos.com.br, Alexandre Brum
<alexandre_b...@...> escreveu
>
> Bom dia Wilson
>  
> O Oracle que estou usando é 9i. Acredito que o comando MERGE está
disponível a partir da 10g. Estranhamente esta procedure gastou apenas
7 min para rodar no meu micro, mas no servidor está gastando quase 2h.
>  
> Configuração do meu micro:
>  
> Intel Core(TM)2 Duo 
> E4600 2.40 GHz
> 1.20 GHz, 1,98 GB de Ram
>  
>  
> Configuração do Servidor:
>  
>  
> HP DL 580
> 4 Processadores Intel Xeon 2.8 GHz
> 4 HD´s 146 GB
> 4 GB de RAM
> Conexão com um Storage e 100 GB de Volume.
>  
> Obrigado.
> 
> 
> Fique com Deus.
> Um grande abraço.
> 
> Att.
> Alexandre Brum
> 
> --- Em qui, 19/2/09, Wilson Teixeira <wilsonteixeira2...@...> escreveu:
> 
> De: Wilson Teixeira <wilsonteixeira2...@...>
> Assunto: Res: [oracle_br] Tuning de Aplicação
> Para: oracle_br@yahoogrupos.com.br
> Data: Quinta-feira, 19 de Fevereiro de 2009, 16:13
> 
> 
> 
> 
> 
> 
> Alexandre,
> 
> você pode tentar realizar esta operacao utilizando o comando MERGE.
> 
> ____________ _________ _________ __
> De: Alexandre Brum <alexandre_brum@ yahoo.com. br>
> Para: oracle...@yahoogrup os.com.br
> Enviadas: Quinta-feira, 19 de Fevereiro de 2009 11:45:51
> Assunto: [oracle_br] Tuning de Aplicação
> 
> Prezados (as)
>   Tenho uma procedure que atualiza dados de uma tabela "A" para a
tabela "B". A tabela "A" não possui nenhum índice.
> Foi carregada através do loader. A procedure procura primeiro
inserir o registro da tabela "A" na tabela "B", caso o
> registro exista na tabela "B", então ocorre uma excecption e através
do WHEN DUP_VAL_ON_INDEX a procecure executa um
> Update na tabela "B" com os dados da tabela "A". 
>   Esse processo está demorando em média 2h. Estou procurando uma
forma de reduzir esse tempo. Se alguém tiver uma sugestão, 
> agradeço antecipadamente. Alguns dados importantes sobre esse cenário:
>   Tabela "A":  1.343.656 de registros;
>                Não possui índices;
>   
>   Tabela "B":  1.953.678 de registros;
>                Índices:
>                   PK_PRAZO_ACC - Coluna ID_PRAZO_ACC
>                   UK_PRAZO_ACC - Coluna ID_LINHA_ORDEM_ COMPRA
>                   
>                Na cláusula WHERE do Update o índice UK_PRAZO_ACC
está sendo utilizado;  
>                No comando Insert está sendo utilizado:
>                   /*+ APPEND */
>                   NOLOGGING
>                   
>                No comando Update está sendo utilizado:
>                   NOLOGGING
>   
>   Microsoft Windows Server 2003
>   Service Pack for Microsoft Windows Server 2003 2
>   Oracle9i Database Enterprise/Standard Edition for Windows 9.2.0. 1
>   Patch Upgrade for Windows Server 2003 (32-bit) - requires 9.2.01
installation  OUI220180
>   Patch Set # 9203WIN2K3
>   Patch # p3095277_9204_ WINNT
>                                    
>   Abaixo segue a procedure na íntegra:
>   
>   CREATE OR REPLACE PROCEDURE ECARGA.AI_PRAZO_ ACC IS
>   --
>   CURSOR C_TAB IS
>   SELECT /*+ FIRST_ROWS(100000) */ 
> Prazo_Entrega
> ,MAX(Dt_Criacao) AS Dt_Criacao
> ,Dt_Atualizacao
> ,NR_Contrato
> ,NR_Ordem_Compra
> ,ID_Ordem_Compra
> ,ID_Linha_Ordem_ compra
> ,ID_Organizacao
> ,NR_LINHA_ORDEM_ COMPRA
>   FROM A_PRAZO_ACC
>   GROUP BY
>   Prazo_Entrega
> ,Dt_Atualizacao
> ,NR_Contrato
> ,NR_Ordem_Compra
> ,ID_Ordem_Compra
> ,ID_Linha_Ordem_ compra
> ,ID_Organizacao
> ,NR_LINHA_ORDEM_ COMPRA
> ;
>   --
>   V_CONT    NUMBER := 0;        -- CONTADOR GERAL DE REGISTROS
>   --
>   TYPE FILE_TYPE  IS RECORD ( ID BINARY_INTEGER) ;
>   --
>   ARQ      UTL_FILE.FILE_ TYPE; -- ARQUIVO QUE LOGA OS ERROS
>   --
>   V_LOCAL_ERRO    VARCHAR2(6);
>   --
>   V_DADOS_ERRO    VARCHAR2(4000) ;
>   --
>   procedure log_erro(P_LOCAL_ ERRO varchar2, P_DADOS_ERRO varchar2) is
>      --
>      ARQ1      UTL_FILE.FILE_ TYPE; -- ARQUIVO QUE LOGA OS ERROS
>      --
>   begin
>       --
>       IF NOT UTL_FILE.IS_ OPEN(ARQ1) THEN
>         --
>         ARQ1 := UTL_FILE.FOPEN( 'C:\DADOS\ ARQUIVOS_ GERADOS_DO_
ORACLE\CARGA\ ERRO_PROC' , 'AI_PRAZO_ACC. TXT','W', 5000);
>         --
>       END IF;
>       --
>       UTL_FILE.PUT_ LINE(ARQ1, P_LOCAL_ERRO| |' '||P_DADOS_ERRO| |'
'||SQLERRM);
>       --
>   end;
>   --
> BEGIN
>   --
>   FOR R_TAB IN C_TAB LOOP
>     --
>     V_DADOS_ERRO := TO_CHAR(SYSDATE, 'DD/MM/YYYY HH24:MI:SS')
||'ID_Linha_ Ordem_compra= ' ||  R_TAB.ID_Linha_ Ordem_compra;
>     --
>     BEGIN
>       --
>       V_LOCAL_ERRO := 'INSERT';
>       --
>       INSERT /*+ APPEND */ INTO PRAZO_ACC NOLOGGING
>       (ID_PRAZO_ACC
> ,Prazo_Entrega
> ,Dt_Criacao
> ,Dt_Atualizacao
> ,NR_Contrato
> ,NR_Ordem_Compra
> ,ID_Ordem_Compra
> ,ID_Linha_Ordem_ compra
> ,ID_Organizacao
> ,NR_linha_Ordem_ Compra
>       )
>       VALUES
>       (SEQ_PRAZO_ACC. NEXTVAL
> ,R_TAB.Prazo_ Entrega
> ,R_TAB.Dt_Criacao
> ,R_TAB.Dt_Atualizac ao
> ,R_TAB.NR_Contrato
> ,R_TAB.NR_Ordem_ Compra
> ,R_TAB.ID_Ordem_ Compra
> ,R_TAB.ID_Linha_ Ordem_compra
> ,R_TAB.ID_Organizac ao
> ,R_TAB.NR_linha_ Ordem_Compra
>       );
>       --
>       V_CONT := V_CONT + 1;
>       --
>       IF V_CONT = 100000 THEN
>         --
>         V_CONT := 0;
>         --
>         COMMIT;
>         --
>       END IF;
>       --
>     EXCEPTION
>       --
>       WHEN DUP_VAL_ON_INDEX THEN
>         --
>         BEGIN
>           --
>           V_LOCAL_ERRO := 'UPDATE';
>           --
>           UPDATE PRAZO_ACC NOLOGGING
>      SET Prazo_Entrega                      = R_TAB.Prazo_ Entrega
>      ,  Dt_Criacao                          = R_TAB.Dt_Criacao
>      ,  Dt_Atualizacao                      = R_TAB.Dt_Atualizaca o
>      ,  NR_Contrato                         = R_TAB.NR_Contrato
>      ,  NR_Ordem_Compra                     = R_TAB.NR_Ordem_ Compra
>      ,  ID_Ordem_Compra                     = R_TAB.ID_Ordem_ Compra
>      ,  ID_Linha_Ordem_ compra               = R_TAB.ID_Linha_
Ordem_compra
>      ,  ID_Organizacao                      = R_TAB.ID_Organizaca o
>      ,  NR_linha_Ordem_ Compra               = R_TAB.NR_linha_
Ordem_Compra
>      WHERE ID_Linha_Ordem_ compra            = R_TAB.ID_Linha_
Ordem_compra;
>           --
>           if sql%notfound then
>              log_erro(V_LOCAL_ ERRO, V_DADOS_ERRO| |' '||SQLERRM);
>           end if;
>           --
>           V_CONT := V_CONT + 1;
>           --
>           IF V_CONT = 100000 THEN
>             --
>             V_CONT := 0;
>             --
>             COMMIT;
>             --
>           END IF;
>           --
>         EXCEPTION
>           --
>           WHEN OTHERS THEN
>             --
>             IF NOT UTL_FILE.IS_ OPEN(ARQ) THEN
>               --
>               ARQ := UTL_FILE.FOPEN( 'C:\DADOS\ ARQUIVOS_
GERADOS_DO_ ORACLE\CARGA\ ERRO_PROC' , 'AI_PRAZO_ACC. TXT','W', 5000);
>               --
>             END IF;
>             --
>             UTL_FILE.PUT_ LINE(ARQ, V_LOCAL_ERRO| |'
'||V_DADOS_ERRO| |' '||SQLERRM);
>             --
>         END;
>           --
>       WHEN OTHERS THEN
>         --
>         IF NOT UTL_FILE.IS_ OPEN(ARQ) THEN
>            --
>            ARQ := UTL_FILE.FOPEN( 'C:\DADOS\ ARQUIVOS_ GERADOS_DO_
ORACLE\CARGA\ ERRO_PROC' , 'AI_PRAZO_ACC. TXT','W', 5000);
>            --
>         END IF;
>         --
>         UTL_FILE.PUT_ LINE(ARQ, V_LOCAL_ERRO| |' '||V_DADOS_ERRO| |'
'||SQLERRM);
>         --
>     END;
>     --
>   END LOOP;
>   --
>   IF UTL_FILE.IS_ OPEN(ARQ) THEN
>     --
>     UTL_FILE.FCLOSE( ARQ);
>     --
>   END IF;
>   --
>   COMMIT;
>   --
> EXCEPTION
>   --
>   WHEN UTL_FILE.INVALID_ PATH OR UTL_FILE.INVALID_ MODE OR
UTL_FILE.INVALID_ OPERATION OR UTL_FILE.INVALID_ FILEHANDLE OR
UTL_FILE.WRITE_ ERROR THEN
>        --
>        IF UTL_FILE.IS_ OPEN(ARQ) THEN
>           --
>           UTL_FILE.PUT_ LINE(ARQ, 'UTL_FILE' ||' '||V_DADOS_ERRO| |'
'||SQLERRM);
>           --
>           UTL_FILE.FCLOSE( ARQ);
>           --
>        ELSE
>           --
>           RAISE_APPLICATION_ ERROR(-20001, SQLERRM);
>           --
>        END IF;
>        --
>        COMMIT;
>        --
>   WHEN OTHERS THEN
>     --
>     IF NOT UTL_FILE.IS_ OPEN(ARQ) THEN
>        --
>        UTL_FILE.PUT_ LINE(ARQ, 'OTHERS'| |' '||V_DADOS_ERRO| |'
'||SQLERRM);
>        --
>        UTL_FILE.FCLOSE( ARQ);
>        --
>     ELSE
>        --
>        RAISE_APPLICATION_ ERROR(-20001, SQLERRM);
>        --
>     END IF;
>     --
>     COMMIT;
>     --
> END;
> /
> 
> Fique com Deus.
> Um grande abraço.
> 
> Att.
> Alexandre Brum
> 
> Veja quais são os assuntos do momento no Yahoo! +Buscados
> http://br.maisbusca dos.yahoo. com
> 
> [As partes desta mensagem que não continham texto foram removidas]
> 
> Veja quais são os assuntos do momento no Yahoo! +Buscados
> http://br.maisbusca dos.yahoo. com
> 
> [As partes desta mensagem que não continham texto foram removidas]
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
>       Veja quais são os assuntos do momento no Yahoo! +Buscados
> http://br.maisbuscados.yahoo.com
> 
> [As partes desta mensagem que não continham texto foram removidas]
>


Responder a