Obrigado pelas respostas pessoal.
É o seguinte, realmente eu entendo que, com o indice, o oracle gera
redo, etc, etc, essa foi a explicação que eu tinha em mente. Mas é
que não pareceu ser problema da inserção de dados em si, porque como
eu disse, foram inseridos poucas linhas, umas 67, e os updates pelo
trace enviado pelo cliente foram bem rápidos. Para exemplificar, eu
fiz um teste no XE, se alguem quiser pode testar também.
Primeiro criei uma tabele com uma pk:
create table teste(id number, valor number)
alter table teste add constraint pk_teste primary key (id)
Depois criei um script para inserir dados nessa tabela:
---
declare
i integer;
PROCEDURE grava(p_id in number, p_valor in number) is
BEGIN
INSERT INTO teste( id, valor) VALUES ( 1, p_valor);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
UPDATE teste
SET valor = valor + p_valor
WHERE id = p_id;
END;
begin
dbms_output.put_line('INICIO: ' || TO_CHAR(SYSDATE, 'DD/MM/
HH24:MI:SS'));
for i in 1 .. 2000 loop
grava(1, 1);
end loop;
dbms_output.put_line('FIM: ' || TO_CHAR(SYSDATE, 'DD/MM/
HH24:MI:SS'));
end;
Executando esse script, demorou uns 40 segundos aqui na minha
máquina. Ai fiz o seguinte teste:
alter table teste disable constraint pk_teste
CREATE INDEX idx_teste ON teste ( id )
E mudei o script para o seguinte:
-
declare
i integer;
PROCEDURE grava(p_id in number, p_valor in number) is
v_achou varchar2(10);
BEGIN
BEGIN
SELECT 'TRUE' INTO v_achou FROM teste WHERE id = p_id;
EXCEPTION WHEN NO_DATA_FOUND THEN
v_achou := 'FALSE';
END;
if v_achou = 'FALSE' then
INSERT INTO teste( id, valor) VALUES ( 1, p_valor);
else
UPDATE teste
SET valor = valor + p_valor
WHERE id = p_id;
end if;
END;
begin
dbms_output.put_line('INICIO: ' || TO_CHAR(SYSDATE, 'DD/MM/
HH24:MI:SS'));
for i in 1 .. 2000 loop
grava(1, 1);
end loop;
dbms_output.put_line('FIM: ' || TO_CHAR(SYSDATE, 'DD/MM/
HH24:MI:SS'));
end;
Esse segundo script demorou 1 segundo. Como podem ver, a única
mudança foi tirar a pk e colocar somente o indice no lugar, e fazer
a verificação "manualmente" antes de inserir os dados. Nos 2
scripts, foram feitos 1 insert e 1999 updates, portanto, acho que
deveria gerar os mesmos números de redos, etc. Inclusive, no segundo
script tem indice pra atualizar também. O problema parece estar na
pk, não sei se para o oracle validar um insert ele executa algumas
tarefas a mais, sei lá, foi por isso que enviei a mensagem, pra ver
se vocês poderiam explicar o porque disso.
Quanto as dicas que deram, acho que não é problema de rebuild do
indice, pois no exemplo que fiz, numa base totalmente limpa, a
difereça de performance é brutal. Quanto as dicas do Chiappa,
infelizmente não da pra fazer somente num select, tem que ser
procedure mesmo porque existem muitas consistencias antes da
gravação, e tem que ser gravado mesmo numa tabela, pois ela vai ser
lido por um outro sistema e eles exigiram que fosse dessa maneira.
Bem, o problema na verdade está resolvido, eu mandei a mensagem
mesmo pra tentar entender porque da pk ser mais lento. Talvez eu
esteja fazendo besteira nesses testes que fiz também, se tiver podem
falar, hehe.
Abraços