Quello che non va con i cursori è che vengono spesso usati in modo improprio, sia in Oracle
e in MS SQL
.
I cursori servono a mantenere un set di risultati stabile che puoi recuperare riga per riga. Vengono creati implicitamente quando viene eseguita la query e chiusi al termine.
Ovviamente mantenere un tale set di risultati richiede alcune risorse:locks
, latches
, memory
, anche disk space
.
Più velocemente queste risorse vengono liberate, meglio è.
Tenere aperto un cursore è come tenere aperta la porta di un frigorifero
Non lo fai per ore senza necessità, ma ciò non significa che non dovresti mai aprire il frigorifero.
Ciò significa che:
- Non ottieni i risultati riga per riga e li sommi:chiami
SQL
èSUM
invece. - Non esegui l'intera query e ottieni i primi risultati dal cursore:aggiungi un
rownum <= 10
condizione alla tua richiesta
, ecc.
Come per Oracle
, l'elaborazione dei cursori all'interno di una procedura richiede il famigerato SQL/PLSQL context switch
cosa che accade ogni volta che ottieni un risultato di un SQL
query fuori dal cursore.
Implica il passaggio di grandi quantità di dati tra i thread e la sincronizzazione dei thread.
Questa è una delle cose più irritanti in Oracle
.
Una delle conseguenze meno evidenti di tale comportamento è che i trigger in Oracle dovrebbero essere evitati, se possibile.
Creazione di un trigger e chiamata a un DML
la funzione è uguale ad aprire il cursore selezionando le righe aggiornate e richiamando il codice di attivazione per ogni riga di questo cursore.
La semplice esistenza del trigger (anche il trigger vuoto) può rallentare un DML
operazione 10 times
o più.
Uno script di prova su 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
secondi senza trigger, 17.57
secondi con un trigger vuoto che non fa nulla.