Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Gespeicherte Oracle-Prozedur, die den Ref-Cursor im Vergleich zu assoziativen Arrays zurückgibt

Die Anfrage des DBA ist nicht sinnvoll.

Was der DBA mit ziemlicher Sicherheit denkt, ist, dass er die Anzahl der SQL-zu-PL/SQL-Engine-Kontextverschiebungen minimieren möchte, die stattfinden, wenn Sie Daten von einem Cursor abrufen. Aber die vorgeschlagene Lösung ist schlecht auf dieses spezielle Problem ausgerichtet und führt in den meisten Systemen zu anderen, viel schwerwiegenderen Leistungsproblemen.

In Oracle tritt eine SQL-zu-PL/SQL-Kontextverschiebung auf, wenn die PL/SQL-VM die SQL-VM nach weiteren Daten fragt, die SQL-VM antwortet, indem sie die Anweisung weiter ausführt, um die Daten zu erhalten, die sie dann verpackt und an die PL zurückgibt /SQL-VM. Wenn die PL/SQL-Engine nacheinander nach Zeilen fragt und Sie viele Zeilen abrufen, ist es möglich, dass diese Kontextverschiebungen einen erheblichen Teil Ihrer Gesamtlaufzeit ausmachen. Um dieses Problem zu bekämpfen, führte Oracle das Konzept der Massenoperationen mindestens in den 8i-Tagen ein. Dadurch konnte die PL/SQL-VM mehrere Zeilen gleichzeitig von der SQL-VM anfordern. Wenn die PL/SQL-VM 100 Zeilen gleichzeitig anfordert, haben Sie 99 % der Kontextverschiebungen eliminiert und Ihr Code wird potenziell viel schneller ausgeführt.

Nachdem Massenoperationen eingeführt wurden, gab es eine Menge Code, der umgestaltet werden konnte, um effizienter zu sein, indem explizit BULK COLLECT verwendet wurde Operationen, anstatt Zeile für Zeile abzurufen und dann FORALL zu verwenden Schleifen, um die Daten in diesen Sammlungen zu verarbeiten. Bis zum 10.2-Tag hatte Oracle jedoch Massenoperationen in das implizite FOR integriert Schleifen also ein implizites FOR -Schleife sammelt jetzt automatisch Massensammlungen in Stapeln von 100, anstatt Zeile für Zeile abzurufen.

Da Sie die Daten in Ihrem Fall jedoch an eine Clientanwendung zurückgeben, ist die Verwendung von Massenvorgängen viel weniger wichtig. Jede anständige clientseitige API verfügt über Funktionen, mit denen der Client angeben kann, wie viele Zeilen bei jedem Netzwerk-Roundtrip vom Cursor abgerufen werden müssen, und diese Abrufanforderungen werden direkt an die SQL-VM gesendet, nicht über die PL /SQL-VM, sodass Sie sich keine Gedanken über Kontextverschiebungen von SQL zu PL/SQL machen müssen. Ihre Anwendung muss sich darum kümmern, bei jedem Roundtrip eine angemessene Anzahl von Zeilen abzurufen – genug, damit die Anwendung nicht zu geschwätzig und zu einem Engpass im Netzwerk wird, aber nicht so viele, dass Sie zu lange auf die Ergebnisse warten müssen zurückgegeben oder um zu viele Daten im Speicher zu speichern.

Die Rückgabe von PL/SQL-Sammlungen anstelle eines REF CURSOR an eine Client-Anwendung wird die Anzahl der stattfindenden Kontextverschiebungen nicht verringern. Aber es wird eine Reihe anderer Nachteile haben, nicht zuletzt die Speichernutzung. Eine PL/SQL-Sammlung muss vollständig in der Process Global Area (PGA) (unter der Annahme dedizierter Serververbindungen) auf dem Datenbankserver gespeichert werden. Dies ist ein Teil des Arbeitsspeichers, der aus dem RAM des Servers zugewiesen werden muss. Das bedeutet, dass der Server Speicher zuweisen muss, um jede letzte Zeile abzurufen, die jeder Client anfordert. Dies wiederum wird die Skalierbarkeit Ihrer Anwendung drastisch einschränken und je nach Datenbankkonfiguration möglicherweise RAM von anderen Teilen der Oracle-Datenbank stehlen, was für die Verbesserung der Anwendungsleistung sehr nützlich wäre. Und wenn Ihnen der PGA-Speicherplatz ausgeht, beginnen Ihre Sitzungen mit speicherbezogenen Fehlern. Selbst in rein PL/SQL-basierten Anwendungen möchten Sie niemals alle Daten in Sammlungen abrufen, Sie möchten sie immer in kleineren Stapeln abrufen, um die Menge an PGA zu minimieren, die Sie verwenden.

Darüber hinaus wird das Abrufen aller Daten in den Speicher dazu führen, dass sich die Anwendung viel langsamer anfühlt. Fast jedes Framework ermöglicht es Ihnen, Daten nach Bedarf abzurufen. Wenn Sie also beispielsweise einen Bericht haben, den Sie auf Seiten mit jeweils 25 Zeilen anzeigen, müsste Ihre Anwendung nur die ersten 25 Zeilen abrufen, bevor sie die erster Bildschirm. Und es müsste niemals die nächsten 25 Zeilen abrufen, es sei denn, der Benutzer fordert zufällig die nächste Ergebnisseite an. Wenn Sie die Daten jedoch wie von Ihrem DBA vorgeschlagen in Arrays abrufen, müssen Sie alle Zeilen abrufen, bevor Ihre Anwendung mit der Anzeige der ersten Zeile beginnen kann, selbst wenn der Benutzer nie mehr als die erste Handvoll sehen möchte Reihen. Das bedeutet viel mehr I/O auf dem Datenbankserver, um alle Zeilen abzurufen, mehr PGA auf dem Server, mehr RAM auf dem Anwendungsserver, um das Ergebnis zu puffern, und längere Wartezeiten für das Netzwerk.