Oracle
 sql >> Database >  >> RDS >> Oracle

Cosa c'è di sbagliato nei cursori?

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.