O que há de errado com os cursores é que eles são frequentemente abusados, tanto no
Oracle
e em MS SQL
. O cursor serve para manter um conjunto de resultados estável que você pode recuperar linha por linha. Eles são criados implicitamente quando sua consulta é executada e fechados quando ela é concluída.
É claro que manter tal conjunto de resultados requer alguns recursos:
locks
, latches
, memory
, até mesmo disk space
. Quanto mais rápido esses recursos forem liberados, melhor.
Manter um cursor aberto é como manter a porta de uma geladeira aberta
Você não faz isso por horas sem necessidade, mas isso não significa que você nunca deve abrir sua geladeira.
Isso significa que:
- Você não obtém seus resultados linha por linha e os soma:você chama o
SQL
'sSUM
em vez disso. - Você não executa a consulta inteira e obtém os primeiros resultados do cursor:você anexa um
rownum <= 10
condição para sua consulta
, etc
Quanto ao
Oracle
, processar seus cursores dentro de um procedimento requer a infame SQL/PLSQL context switch
que acontece toda vez que você obtém um resultado de um SQL
consulta fora do cursor. Envolve passar grandes quantidades de dados entre threads e sincronizar os threads.
Esta é uma das coisas mais irritantes no
Oracle
. Uma das consequências menos evidentes desse comportamento é que os gatilhos no Oracle devem ser evitados, se possível.
Criando um gatilho e chamando um
DML
A função é igual a abrir o cursor selecionando as linhas atualizadas e chamando o código de trigger para cada linha deste cursor. A mera existência do gatilho (mesmo o gatilho vazio) pode retardar um
DML
operação 10 times
ou mais. Um script de teste em
10g
:SQL> CREATE TABLE trigger_test (id INT NOT NULL)
2 /
Table created
Executed in 0,031 seconds
SQL> INSERT
2 INTO trigger_test
3 SELECT level
4 FROM dual
5 CONNECT BY
6 level <= 1000000
7 /
1000000 rows inserted
Executed in 1,469 seconds
SQL> COMMIT
2 /
Commit complete
Executed in 0 seconds
SQL> TRUNCATE TABLE trigger_test
2 /
Table truncated
Executed in 3 seconds
SQL> CREATE TRIGGER trg_test_ai
2 AFTER INSERT
3 ON trigger_test
4 FOR EACH ROW
5 BEGIN
6 NULL;
7 END;
8 /
Trigger created
Executed in 0,094 seconds
SQL> INSERT
2 INTO trigger_test
3 SELECT level
4 FROM dual
5 CONNECT BY
6 level <= 1000000
7 /
1000000 rows inserted
Executed in 17,578 seconds
1.47
segundos sem um acionador, 17.57
segundos com um gatilho vazio sem fazer nada.