- Este tópico contém 15 respostas, 3 vozes e foi atualizado pela última vez 18 anos, 8 meses atrás por
Marcio68Almeida.
-
AutorPosts
-
20 de abril de 2007 às 9:56 pm #79295
kurtrer
ParticipantePessoal, 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
20 de abril de 2007 às 10:16 pm #79297chduarte
ParticipanteAdicione um commit a cada 1000 ou xxxx registros.
[]
20 de abril de 2007 às 10:23 pm #79298kurtrer
ParticipanteMe perdoe esqueci de colocar no código, o commit está a cada 1000 registros.
20 de abril de 2007 às 10:24 pm #79300chduarte
ParticipanteSe for oracle 9i coloque o undo_retention=auto
[]
20 de abril de 2007 às 10:28 pm #79301kurtrer
ParticipanteO 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.
20 de abril de 2007 às 10:29 pm #79302kurtrer
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.20 de abril de 2007 às 10:32 pm #79303chduarte
ParticipanteTem algo estranho pq com o undo_retention = auto é muito dificil dar este erro.
Quanto tempo leva este processo?
20 de abril de 2007 às 10:46 pm #79305kurtrer
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.20 de abril de 2007 às 10:51 pm #79307Marcio68Almeida
Participantebom… 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…20 de abril de 2007 às 10:52 pm #79308chduarte
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.
[]
20 de abril de 2007 às 11:22 pm #79310kurtrer
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.20 de abril de 2007 às 11:31 pm #79311kurtrer
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?
20 de abril de 2007 às 11:49 pm #79313Marcio68Almeida
ParticipanteMeu 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…21 de abril de 2007 às 12:14 am #79314kurtrer
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)21 de abril de 2007 às 12:19 am #79315kurtrer
ParticipanteO 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.
-
AutorPosts
- Você deve fazer login para responder a este tópico.