Warum explizite Cursor anstelle von regulären Schleifen verwenden?

12

Ich schreibe seit einem Jahr grundlegende Web-Apps (für eine Oracle-Datenbank), und da die Funktionen ziemlich einfach sind, halten sich die meisten von uns an reguläre FOR-Schleifen, um unsere Daten abzurufen:

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

Aber Cursor scheinen der „richtige“ Weg zu sein, Dinge zu tun. Ich kann viele Informationen darüber finden, was Cursor sind und wie sie durchlaufen werden, aber ich kann keinen soliden Grund finden, warum ich sie über reguläre FOR-Schleifen verwenden soll. Ist es abhängig von den Erfordernissen des Verfahrens? Gibt es inhärente Vorteile, die ich beachten sollte?

ini
quelle
Diese Art von FORist nur eine andere Möglichkeit, Cursor zu verwenden. Siehe die Dokumente: docs.oracle.com/cd/E11882_01/appdev.112/e10472/… Was macht htp.prn ()?
Dekso
Das ist eine unserer Ausgabefunktionen. Haben Sie eine Präferenz für die zu verwendende Methode?
Ini
Für diese Art von Dingen ist die FORSchleife meiner Meinung nach viel besser lesbar. Ich neige dazu, "echte" Cursor nur zu verwenden, wenn ich rückwärts und nicht nur vorwärts treten muss. Ich habe diese andere Frage gestellt, weil ich mir stattdessen eine Tabellenfunktion vorstellen kann htp.prn().
Dekso
Es ist erwähnenswert, dass beide Cursorformen eine schlechtere Leistung als eine reine SQL-Lösung aufweisen - insbesondere relevant für DML-Anweisungen.
David Aldridge

Antworten:

7

Ein Cursor kann explizit oder implizit sein, und jeder Typ kann in einer FOR-Schleife verwendet werden. Ihre Frage hat wirklich zwei Aspekte.

  1. Warum eine explizite Cursor-FOR-Schleife über einer impliziten Cursor-FOR-Schleife verwenden?

    • Verwenden Sie eine explizite Cursor-FOR-Schleife, wenn die Abfrage wiederverwendet wird. Andernfalls wird ein impliziter Cursor bevorzugt.
  2. Warum sollte eine Schleife mit einem FETCH anstelle einer FOR-Schleife ohne expliziten FETCH verwendet werden?

    • Verwenden Sie einen FETCH in einer Schleife, wenn Sie eine Massenerfassung benötigen oder wenn Sie dynamisches SQL benötigen.

Hier finden Sie einige nützliche Informationen aus der Dokumentation.

Beispiel für einen impliziten Cursor 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;
/

Beispiel für einen expliziten Cursor 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;
/

Impliziter Cursor

Ein impliziter Cursor ist ein Sitzungscursor, der von PL / SQL erstellt und verwaltet wird. PL / SQL öffnet jedes Mal einen impliziten Cursor, wenn Sie eine SELECT- oder DML-Anweisung ausführen. Sie können einen impliziten Cursor nicht steuern, aber Sie können Informationen aus seinen Attributen abrufen.

Ein impliziter Cursor wird geschlossen, nachdem die zugehörige Anweisung ausgeführt wurde. Die Attributwerte bleiben jedoch verfügbar, bis eine andere SELECT- oder DML-Anweisung ausgeführt wird.

Die impliziten Cursorattribute sind: SQL% ISOPEN, SQL% FOUND, SQL% NOTFOUND, SQL% ROWCOUNT, SQL% BULK_ROWCOUNT, SQL% BULK_EXCEPTIONS

Expliziter Cursor

Ein expliziter Cursor ist ein Sitzungscursor, den Sie erstellen und verwalten. Sie müssen einen expliziten Cursor deklarieren und definieren, ihm einen Namen geben und ihn einer Abfrage zuordnen (normalerweise gibt die Abfrage mehrere Zeilen zurück). Anschließend können Sie die Abfrageergebnismenge auf eine der folgenden Arten verarbeiten:

Öffnen Sie den expliziten Cursor (mit der Anweisung OPEN), rufen Sie Zeilen aus der Ergebnismenge ab (mit der Anweisung FETCH) und schließen Sie den expliziten Cursor (mit der Anweisung CLOSE).

Verwenden Sie den expliziten Cursor in einer Cursor-FOR-LOOP-Anweisung (siehe "Verarbeitung der Abfrageergebnismenge mit Cursor-FOR-LOOP-Anweisungen").

Sie können einem expliziten Cursor keinen Wert zuweisen, ihn nicht in einem Ausdruck verwenden oder als formalen Unterprogrammparameter oder Hostvariable verwenden. Sie können diese Dinge mit einer Cursor-Variablen tun (siehe "Cursor-Variablen").

Im Gegensatz zu einem impliziten Cursor können Sie einen expliziten Cursor oder eine Cursor-Variable anhand ihres Namens referenzieren. Daher wird ein expliziter Cursor oder eine Cursor-Variable als benannter Cursor bezeichnet.

Cursor FOR LOOP-Anweisungen

Mit der Cursor-Anweisung FOR LOOP können Sie eine SELECT-Anweisung ausführen und dann sofort die Zeilen der Ergebnismenge durchlaufen. Diese Anweisung kann entweder einen impliziten oder einen expliziten Cursor verwenden.

Leigh Riffel
quelle
1
Implizite Cursor rufen ab 10 g jeweils 100 Zeilen ab.
David Aldridge
16

Der von Ihnen gepostete Code verwendet einen Cursor. Es wird eine implizite Cursorschleife verwendet.

Es gibt Fälle, in denen die Verwendung einer expliziten Cursorschleife (dh das Deklarieren einer CURSOR-Variablen im Deklarationsabschnitt) entweder saubereren Code oder eine bessere Leistung erzeugt

  1. Wenn Sie komplexere Abfragen haben, die Sie nicht in Ansichten umgestalten können, kann der Code leichter gelesen werden, wenn Ihre Schleife wiederholt wird student_cursoranstatt eine 30-zeilige SQL-Anweisung einzuschließen, in die eine Reihe von Logik eingebettet ist. Wenn Sie beispielsweise alle Studenten ausgedruckt haben, die für den Abschluss freigegeben wurden und an Tabellen mit ihren akademischen Aufzeichnungen, den Anforderungen ihres Studiengangs, Tabellen mit Informationen zu akademischen Beständen, Tabellen mit Informationen zu überfälligen Bibliotheksbüchern teilnehmen mussten, Tabellen mit Informationen zu nicht bezahlten Gebühren, administrativen Überschreibungen usw. Es wäre wahrscheinlich sinnvoll, den Code so umzugestalten, dass diese Abfrage nicht in der Mitte des Codes steckt, der die Präsentation der Liste für einen Benutzer betrifft. Dies könnte das Erstellen einer Ansicht beinhalten, die all diese Logik zusammenfasst. Oder es kann ein expliziter Cursor erstellt werden, der entweder als Teil des aktuellen PL / SQL-Blocks oder in einem übergeordneten PL / SQL-Block deklariert wurde (d. H. ein in einem Paket deklarierter Cursor), damit er wiederverwendbar ist. Oder Sie müssen etwas anderes für die Kapselung und Wiederverwendbarkeit tun (z. B. stattdessen eine Pipeline-Tabellenfunktion erstellen).
  2. Wenn Sie Massenoperationen in PL / SQL verwenden möchten, möchten Sie im Allgemeinen explizite Cursor verwenden. Hier ist ein StackOverflow-Thread, in dem die Leistungsunterschiede zwischen expliziten und impliziten Cursorn erläutert werden . Wenn Sie nur anrufen htp.prn, BULK COLLECTkaufen Sie wahrscheinlich nichts. In anderen Fällen kann dies jedoch zu erheblichen Leistungsverbesserungen führen.
Justin Cave
quelle
2

Ich sehe, dass viele Entwickler explizite Cursor anstelle impliziter Cursor aus alter Gewohnheit verwenden. Dies liegt daran, dass dies in Oracle Version 7 immer der effizientere Weg war. Heutzutage gibt es im Allgemeinen den umgekehrten Weg. Insbesondere mit dem Optimierer, der bei Bedarf den impliziten Cursor für Schleifen in eine Massenerfassung umschreiben kann.

Peter Åkerlund
quelle
0

Kürzlich musste ich eine Reihe von Abfragen aus einer impliziten FOR-Schleife in explizite Cursor umschreiben. Der Grund war, dass die Abfragen Daten aus einer externen Datenbank über einen Link abriefen und diese Datenbank eine andere Codierung hatte als unsere lokale Datenbank. Beim Übertragen von Daten vom impliziten Cursor in einen lokal definierten Datensatztyp traten mysteriöse intermittierende Fehler auf (nur in bestimmten Zeilen). Unser DBA hat uns das erklärt, wir hätten dem selbst nicht auf den Grund gehen können. Es scheint, dass dies ein Fehler in Oracle ist, der gemeldet wurde.

Es wurde uns empfohlen, alles mit expliziten Cursorn neu zu schreiben, und der Fehler war behoben.

Nicht der Hauptgrund, warum Sie explizit über implizit verwenden möchten, aber eine Anmerkung wert.

BEARBEITEN: Oracle 12c.

Robotron
quelle
Könnten Sie den Fehler und / oder die Notiznummer hinzufügen, damit diejenigen, die dies lesen, mehr über die Symptome erfahren und ob / wann dies behoben ist?
Leigh Riffel
Entschuldigung, die Fehlerberichterstattung wurde von einem unserer Datenbankadministratoren durchgeführt. Ich habe keinen Zugriff auf diese Informationen.
Robotron