Perché usare i cursori espliciti anziché i cicli regolari?


12

Sto scrivendo app Web di base da un anno (per un db Oracle) e poiché le funzioni sono piuttosto semplici, la maggior parte di noi si attacca ai normali cicli FOR per ottenere i nostri dati:

for i in (select * from STUDENTS) loop
      htp.prn(i.student_last_name || ', ' || i.student_first_name || ' ' || i.student_dob);
end loop;

Ma i cursori sembrano essere il modo "giusto" per fare le cose. Riesco a trovare molte informazioni su cosa sono i cursori e sui diversi modi per collegarli, ma non riesco a trovare una solida ragione per usarli nei normali cicli FOR. Dipende dalle esigenze della procedura? Ci sono vantaggi intrinseci di cui dovrei essere a conoscenza?


Questo tipo di FORè solo un altro modo di usare i cursori. Vedi i documenti: docs.oracle.com/cd/E11882_01/appdev.112/e10472/… Comunque, cosa fa htp.prn ()?
dezso,

Questa è una delle nostre funzioni di output. Quindi, hai una preferenza su quale metodo utilizzare?
ini

Per questo tipo di cose il FORciclo è molto più leggibile, credo. Tendo a usare cursori "reali" solo se devo fare un passo indietro, non solo in avanti. Ho fatto quell'altra domanda perché posso immaginare una funzione tabella anziché htp.prn().
dezso,

Vale la pena ricordare che entrambe le forme di cursore hanno prestazioni inferiori a una soluzione SQL pura, particolarmente rilevante per le istruzioni DML.
David Aldridge,

Risposte:


7

Un cursore può essere esplicito o implicito ed entrambi i tipi possono essere utilizzati in un ciclo FOR. Ci sono davvero due aspetti della tua domanda.

  1. Perché utilizzare un ciclo FOR cursore esplicito su un ciclo FOR cursore implicito?

    • Utilizzare un ciclo FOR cursore esplicito quando la query verrà riutilizzata, altrimenti si preferisce un cursore implicito.
  2. Perché usare un loop con un FETCH anziché un ciclo FOR che non ha un FETCH esplicito?

    • Utilizzare un FETCH all'interno di un ciclo quando è necessario eseguire la raccolta collettiva o quando è necessario SQL dinamico.

Ecco alcune informazioni utili dalla documentazione.

Esempio di cursore implicito FOR LOOP

BEGIN
   FOR vItems IN (
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name
   ) 
   LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Esempio di cursore esplicito FOR LOOP

DECLARE
   CURSOR c1 IS
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name;
BEGIN
   FOR vItems IN c1 LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

Cursore implicito

Un cursore implicito è un cursore di sessione creato e gestito da PL / SQL. PL / SQL apre un cursore implicito ogni volta che si esegue un'istruzione SELECT o DML. Non puoi controllare un cursore implicito, ma puoi ottenere informazioni dai suoi attributi.

Un cursore implicito si chiude dopo l'esecuzione dell'istruzione associata; tuttavia, i valori dei suoi attributi rimangono disponibili fino a quando non viene eseguita un'altra istruzione SELECT o DML.

Gli attributi del cursore implicito sono: SQL% ISOPEN, SQL% FOUND, SQL% NOTFOUND, SQL% ROWCOUNT, SQL% BULK_ROWCOUNT, SQL% BULK_EXCEPTIONS

Cursore esplicito

Un cursore esplicito è un cursore di sessione che costruisci e gestisci. È necessario dichiarare e definire un cursore esplicito, assegnandogli un nome e associandolo a una query (in genere, la query restituisce più righe). Quindi è possibile elaborare il set di risultati della query in uno dei seguenti modi:

Aprire il cursore esplicito (con l'istruzione OPEN), recuperare le righe dal set di risultati (con l'istruzione FETCH) e chiudere il cursore esplicito (con l'istruzione CLOSE).

Utilizzare il cursore esplicito in un'istruzione FOR LOOP del cursore (consultare "Elaborazione del set di risultati della query con istruzioni cursore FOR LOOP").

Non è possibile assegnare un valore a un cursore esplicito, utilizzarlo in un'espressione o utilizzarlo come parametro di sottoprogramma formale o variabile host. Puoi fare queste cose con una variabile cursore (vedi "Variabili cursore").

A differenza di un cursore implicito, è possibile fare riferimento a un cursore esplicito o a una variabile cursore in base al nome. Pertanto, un cursore esplicito o una variabile cursore viene chiamato cursore denominato.

Dichiarazioni cursore per LOOP

Il cursore FOR LOOP consente di eseguire un'istruzione SELECT e di scorrere immediatamente le righe del set di risultati. Questa affermazione può usare un cursore implicito o esplicito.


1
I cursori impliciti recuperano 100 righe alla volta da 10 g in poi.
David Aldridge,

16

Il codice che hai pubblicato sta usando un cursore. Sta usando un loop cursore implicito.

Ci sono casi in cui l'utilizzo di un loop cursore esplicito (ovvero la dichiarazione di una variabile CURSOR nella sezione dichiarazione) produce codice più pulito o prestazioni migliori

  1. Se hai query più complesse che non puoi trasformare nelle viste, può rendere più semplice la lettura del codice se il tuo ciclo scorre ripetutamente student_cursorpiuttosto che includere un'istruzione SQL a 30 righe che incorpora un sacco di logica. Ad esempio, se stavi stampando tutti gli studenti che sono stati autorizzati a laurearsi e che hanno coinvolto l'unione a tavoli che avevano i loro documenti accademici, i requisiti del loro programma di laurea, tabelle con informazioni su titoli accademici, tabelle con informazioni sui libri in biblioteca scaduti, tabelle con informazioni su commissioni non pagate, sovrascritture amministrative, ecc. probabilmente avrebbe senso riformattare il codice in modo che questa query non fosse bloccata nel mezzo del codice che si preoccupa di presentare l'elenco a un utente. Ciò potrebbe comportare la creazione di una vista che incapsuli tutta questa logica. Oppure potrebbe comportare la creazione di un cursore esplicito che è stato dichiarato come parte del blocco PL / SQL corrente o in alcuni blocchi PL / SQL di livello superiore (ad es. un cursore dichiarato in un pacchetto) in modo che sia riutilizzabile. Oppure potrebbe implicare di fare qualcos'altro per l'incapsulamento e la riusabilità (diciamo, invece, creando una funzione tabella pipeline).
  2. Se si desidera utilizzare operazioni in blocco in PL / SQL, in genere si desidera utilizzare cursori espliciti. Ecco un thread StackOverflow che discute le differenze di prestazioni tra cursori espliciti e impliciti . Se tutto ciò che stai facendo è chiamare htp.prn, BULK COLLECTprobabilmente non ti compri nulla. In altri casi, tuttavia, può comportare miglioramenti sostanziali delle prestazioni.

2

Vedo che molti sviluppatori utilizzano cursori espliciti invece di cursori impliciti per vecchia abitudine. Questo perché in Oracle versione 7 questo era sempre il modo più efficiente di procedere. Oggi ci sono generalmente il contrario. Specialmente con l'ottimizzatore che, se necessario, può riscrivere il cursore implicito per i loop in una raccolta di massa.


0

Di recente ho dovuto riscrivere un mucchio di query da un ciclo FOR implicito in cursori espliciti. Il motivo è che le query hanno recuperato i dati da un database esterno tramite link e questo database aveva una codifica diversa rispetto al nostro database locale. Durante il trasferimento di dati dal cursore implicito in un tipo di record definito localmente si sono verificati misteriosi errori intermittenti (solo su determinate righe specifiche). Il nostro DBA ci ha spiegato questo, non saremmo stati in grado di arrivare fino in fondo da soli. Sembra che sia stato segnalato un bug in Oracle.

Ci è stato consigliato di riscrivere tutto usando i cursori espliciti e l'errore era sparito.

Non è il motivo principale per cui potresti voler usare esplicito su implicito, ma merita una nota.

EDIT: Oracle 12c.


Potresti aggiungere il numero di bug e / o nota in modo che coloro che leggono questo possano sapere di più sui sintomi e se / quando questo è risolto?
Leigh Riffel,

Siamo spiacenti, la segnalazione di bug è stata effettuata da uno dei nostri DBA, non ho accesso a tali informazioni.
Robotron,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.