Pular para o conteúdo
  • Este tópico contém 15 respostas, 3 vozes e foi atualizado pela última vez 18 anos, 8 meses atrás por Marcio68Almeida.
Visualizando 15 posts - 1 até 15 (de 16 do total)
  • Autor
    Posts
  • #79295
    kurtrer
    Participante

      Pessoal, boa tarde!!

      Estou com um pequeno probleminha aqui, estou com um processo de copia de registros da tabela A para a tabela A_HIST, ele está me retornando o erro snapshot too old, o segmento de rollback já está no máximo que os bancos de testes suportam, a lógica da rotina está da seguinte forma:


      declare
      cursor cA is Select * from tabelaA;
      begin
      for curA in cA loop
      begin
      insert into tabelaA_Hist values curA
      exception
      when dup_val_on_index then
      null;
      when others then
      null;
      end;
      end loop;
      end;

      Esse processo é executado em 7 tabelas diferentes, o erro não ocorre sempre na mesma tabela, alguém conhece alguma outra forma de evitar esse erro?

      Grato

      #79297
      chduarte
      Participante

        Adicione um commit a cada 1000 ou xxxx registros.

        []

        #79298
        kurtrer
        Participante

          Me perdoe esqueci de colocar no código, o commit está a cada 1000 registros.

          #79300
          chduarte
          Participante

            Se for oracle 9i coloque o undo_retention=auto

            []

            #79301
            kurtrer
            Participante

              O código está estruturado da seguinte forma:

              SELECT COUNT(1)
              INTO V_TOT_REGISTROS
              FROM TABELA
              --
              V_QT_ITERACOES := CEIL(V_TOT_REGISTROS / 25000);
              --
              V_INS_AUX := 0;
              V_COUNT_COMMIT := 0;
              V_REG_INICIO := 1;
              FOR ITERATOR IN 1 .. V_QT_ITERACOES LOOP
              FOR C_CONSTR IN C_CONST (V_REG_INICIO, ITERATOR * 25000) LOOP
              BEGIN
              V_REC_CONSTR := C_CONSTR;

                    PROC_INSERE_CONST( P_TYP_REC_CONST    => V_REC_CONSTR
                                          , P_IC_TIPO_REGISTRO => V_IC_TIPO_REGISTRO
                                          , P_CD_RETORNO       => V_CD_RETORNO_THROU
                                          );
                  END;
                  --
                  IF V_COUNT_COMMIT MOD V_CONTROLE_COMMIT = 0 AND
                     V_COUNT_COMMIT != 0 THEN -- SO INSERE A CADA 1000 REGISTROS
                    IF V_ERRO = 0 THEN -- SE NAO TIVERAM ERROS
                      V_TOT_INS_CONSTR_V := V_TOT_INS_CONSTR_V + V_INS_AUX;
                      V_INS_AUX := 0;
                      V_ERRO := 0;
                      COMMIT;
                    ELSE
                      V_ERRO := 0;
                      ROLLBACK;
                    END IF;
                  END IF;
                END LOOP; -- C_CONSTR
                --
                V_REG_INICIO := V_REG_INICIO + 25000;
                --
              END LOOP;
              --
              -- REGISTROS RESTANTES
              IF V_ERRO = 0 THEN  
                V_TOT_INS_CONSTR_V := V_TOT_INS_CONSTR_V + V_INS_AUX;
                V_INS_AUX := 0;
                V_ERRO := 0;
                COMMIT;
              ELSE
                V_ERRO := 0;
                ROLLBACK;
              END IF;
              

              PS: A PROC_INSERE_CONST executa apenas o insert na tabela referente.

              #79302
              kurtrer
              Participante

                [quote=”chduarte”:2f39cc6s]Se for oracle 9i coloque o undo_retention=auto

                [][/quote]
                Eu questionei nossa DBA a respeito disso, e ela disse que já estava com undo_retention = auto.

                #79303
                chduarte
                Participante

                  Tem algo estranho pq com o undo_retention = auto é muito dificil dar este erro.

                  Quanto tempo leva este processo?

                  #79305
                  kurtrer
                  Participante

                    [quote=”chduarte”:24evovkh]Tem algo estranho pq com o undo_retention = auto é muito dificil dar este erro.

                    Quanto tempo leva este processo?[/quote]
                    Não sei ainda, porque eu não consegui roda-lo até o fim 🙁 , mas por estimativa, vai demorar em torno de umas 7 horas.
                    O total de registros nas tabelas chega quase a 100.000.000.

                    #79307
                    Marcio68Almeida
                    Participante

                      bom… com uma quantidade cavalar dessas é bem normal que dê erro…
                      você está lendo uma tabela enorme, criando um cursor depois inserindo registro a registro…
                      não dá para inserir massivamente ? insert into as select ??? deve doer menos no banco e demorar menos também…

                      #79308
                      chduarte
                      Participante

                        é, entao vc vai ter realmente problemas se alguem estiver mexendo nesta tabela pq o banco nao consegue segurar informacao por tanto tempo.

                        Talvez vc precise mudar a estrategia com tantas linhas, como por exemplo gerar um export da tabela e fazer um import ou via dataload ou dar um lock excluisive na tabela enquanto estiver fazendo a carga.

                        boa sorte.

                        []

                        #79310
                        kurtrer
                        Participante

                          [quote=”Marcio68Almeida”:3is8zyft]bom… com uma quantidade cavalar dessas é bem normal que dê erro…
                          você está lendo uma tabela enorme, criando um cursor depois inserindo registro a registro…
                          não dá para inserir massivamente ? insert into as select ??? deve doer menos no banco e demorar menos também…[/quote]
                          Mas fazendo a inserção dessa forma, como vou tratar os commits?
                          Obs: são sete tabelas, mas uma é sem educação tem mais de 60.000 registros, e o pior, o erro está dando em uma tabela anterior a ela.

                          #79311
                          kurtrer
                          Participante

                            [quote=”chduarte”:1j529he0]é, entao vc vai ter realmente problemas se alguem estiver mexendo nesta tabela pq o banco nao consegue segurar informacao por tanto tempo.

                            Talvez vc precise mudar a estrategia com tantas linhas, como por exemplo gerar um export da tabela e fazer um import ou via dataload ou dar um lock excluisive na tabela enquanto estiver fazendo a carga.

                            boa sorte.

                            [][/quote]
                            Na mensagem acima faltou tres zeros, o correto seria 60.000.000.

                            Esse processo vai ser executado após o expediente, via crontab, então não vai ter nenhum outro processo ou pessoa executando junto comigo, e no nosso banco de testes só tem meu usuário logado.

                            Alguma outra idéia?

                            #79313
                            Marcio68Almeida
                            Participante

                              Meu conselho é que você faça o processo em etapas…
                              divida a tabela a ser inserida em pedaços e coloque uma cláusula where between para cada processo, faça um loop semelhante ao que você já tem, processando cinquenta mil linhas por vez…
                              fazer uma carga de sessenta milhões de linhas, uma por uma, vai derrubar o banco com certeza…
                              vTotal = tamanho da tabela / 50000
                              loop de i a vTotal
                              insert into tabela1 as select * from tabela2 where registro between i + (( i -1 ) * 50000) and i * 50000
                              end loop

                              algo parecido com isto…

                              #79314
                              kurtrer
                              Participante

                                [quote=”kurtrer”:198tevg5]O código está estruturado da seguinte forma:

                                SELECT COUNT(1)
                                INTO V_TOT_REGISTROS
                                FROM TABELA
                                --
                                V_QT_ITERACOES := CEIL(V_TOT_REGISTROS / 25000);
                                --
                                V_INS_AUX := 0;
                                V_COUNT_COMMIT := 0;
                                V_REG_INICIO := 1;
                                FOR ITERATOR IN 1 .. V_QT_ITERACOES LOOP
                                FOR C_CONSTR IN C_CONST (V_REG_INICIO, ITERATOR * 25000) LOOP
                                BEGIN
                                V_REC_CONSTR := C_CONSTR;

                                      PROC_INSERE_CONST( P_TYP_REC_CONST    => V_REC_CONSTR
                                                            , P_IC_TIPO_REGISTRO => V_IC_TIPO_REGISTRO
                                                            , P_CD_RETORNO       => V_CD_RETORNO_THROU
                                                            );
                                    END;
                                    --
                                    IF V_COUNT_COMMIT MOD V_CONTROLE_COMMIT = 0 AND
                                       V_COUNT_COMMIT != 0 THEN -- SO INSERE A CADA 1000 REGISTROS
                                      IF V_ERRO = 0 THEN -- SE NAO TIVERAM ERROS
                                        V_TOT_INS_CONSTR_V := V_TOT_INS_CONSTR_V + V_INS_AUX;
                                        V_INS_AUX := 0;
                                        V_ERRO := 0;
                                        COMMIT;
                                      ELSE
                                        V_ERRO := 0;
                                        ROLLBACK;
                                      END IF;
                                    END IF;
                                  END LOOP; -- C_CONSTR
                                  --
                                  V_REG_INICIO := V_REG_INICIO + 25000;
                                  --
                                END LOOP;
                                --
                                -- REGISTROS RESTANTES
                                IF V_ERRO = 0 THEN  
                                  V_TOT_INS_CONSTR_V := V_TOT_INS_CONSTR_V + V_INS_AUX;
                                  V_INS_AUX := 0;
                                  V_ERRO := 0;
                                  COMMIT;
                                ELSE
                                  V_ERRO := 0;
                                  ROLLBACK;
                                END IF;
                                

                                PS: A PROC_INSERE_CONST executa apenas o insert na tabela referente.[/quote]
                                Marcio68Almeida, obrigado pela ajuda, o código que estou rodando, estou fazendo em etapas mesmo, eu tenho um for dentro do outro, sendo o primeiro que controla quantas vezes eu vou ter que faze-lo e o outro é o for do cursor, que controla as linhas que eu quero que trata, por exemplo da linha 1 até a 25000, depois ele vai trazer da 25001 até 50000 e assim sucessivamente.
                                FOR ITERATOR IN 1 .. V_QT_ITERACOES LOOP
                                FOR C_CONSTR IN C_CONST (V_REG_INICIO, ITERATOR * 25000)

                                #79315
                                kurtrer
                                Participante

                                  O cursor é o seguinte

                                  CURSOR C_CONST( PC_REG_INICIO NUMBER
                                  , PC_REG_FIM NUMBER
                                  ) IS
                                  SELECT *
                                  FROM ( SELECT TOPN.*
                                  , ROWNUM RNUM
                                  FROM ( SELECT *
                                  FROM CONSTRUCAO
                                  WHERE ( DT_EFETIVAR = SYSDATE
                                  )
                                  OR ( DT_EFETIVAR > SYSDATE
                                  AND DT_DESCONTINUAR > SYSDATE
                                  ) ) TOPN
                                  WHERE ROWNUM = PC_REG_INICIO;

                                  Eu peguei a idéia de uma materia na revista da Oracle de uns meses atrás, lá dizia que essa era a melhor forma de trazer ranges de dados de uma tabela.

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