Einzelnen Beitrag anzeigen

Robert_G
(Gast)

n/a Beiträge
 
#3

Re: Große Datenmengen in Oracle 9i häppchenweise fetchen

  Alt 26. Sep 2004, 21:58
Zitat von omata:
500000 Datensätze ergaben eine CSV-Datei von 26MB und das dauerte 1 Min 10 Sec. (das hängt natürlich von der Rechnergeschwindigkeit ab)
Eben, in den 20 - 30 Sekunden bis die Daten da sind, würde der User nicht wissen was gerade passiert, bzw. wieweit das Programm schon ist.
Zitat von omata:
Aber, wenn das so viele Datensätze sind dauert das naturlich auch eine gewisse Zeit.
Mit mehreren Abfragen würde ich das nicht so gut finden, weil dann in der Zwischenzeit Änderungen stattfinden könnten (Mehrbenutzerfähigkeit).
Ein Ref Cursor ist _EINE_ Abfrage, du kannst über ihn, als Refferenz, die gleiche Ergebnismenge an unterschiedlichen Stellen verwenden.
Deshalb war der Ansatz von deefens schon ganz OK.
IMHO hast du jetzt 2 Möglichkeiten:
  • Die CoreLabs-Kompos erlauben dir eine gewisse Cache-Größe zu bestimmen. (zum Bleistift soll er nur alle 1,000 Records die nächsten 1,000 holen)
  • oder, du musst den Kampf da unten aufnehmen.
Das Problem, was ich jetzt sehe, ist das du das ganze als Bind variablen auslesen und übergeben musst.
Deshalb fällt eine "table of record" weg. (Ist ja ein PL/SQL-Typ, kein SQL-Typ )
Möglich wäre jetzt ein SQL Typ und ein weiterer SQL Typ als "table of [deinTyp]".
SQL-Code:
create or replace type rec$F_VBO_DC_OVERVIEW as Object
(
  /* Hier sollten alle nötigen Spalten (in der richtigen Reihenfolge !!!) stehen */
  A Integer
 ,B Varchar2(200)
 ,C Varchar2(20)
)
Der Tabellentyp:
create ore replace type tbl$F_VBO_DC_OVERVIEW as table of rec$F_VBO_DC_OVERVIEW Ein Package, in dem alle nötigen Functionen stehen könnte so aussehen:
  • Spec:
    SQL-Code:
    create or replace package TestCurPck is
      cursor CursorJustForOpening is
        /* default constructor deines Typs (auch hier die Spaltenreihenfolge beachten!) */
        SELECT rec$F_VBO_DC_OVERVIEW(A
                                    ,B
                                    ,C)
        FROM F_VBO_DC_OVERVIEW;

      type StrongTypedRefCur is
        Ref Cursor return CursorJustForOpening%RowType;

      function OpenCursor return StrongTypedRefCur;

      function FetchRecs
      (
        iCur in StrongTypedRefCur
       ,iRecLimit in Integer
       ,ioTable in out nocopy tbl$F_VBO_DC_OVERVIEW
      ) return integer;

    end TestCurPck;
  • Body:
    SQL-Code:
    create or replace package body TestCurPck is

      function OpenCursor return StrongTypedRefCur is
        oCur StrongTypedRefCur;
      begin
        open CursorJustForOpening;
        oCur := CursorJustForOpening;
        return oCur;
      end;
      
      function FetchRecs
      (
        iCur in StrongTypedRefCur
       ,iRecLimit in Integer
       ,ioTable in out nocopy tbl$F_VBO_DC_OVERVIEW
      ) return integer is
      begin
        fetch iCur
          bulk collect into ioTable
          limit iRecLimit;
        if iCur%NotFound then
          return 1;
        else
          return 0;
        end if;
      end;

    end TestCurPck;
Da ich jetzt hier zu Hause nur meine eigene Ora 8.16 Personal Lizenz habe, kann ich das gute alte WeakTyped/StongTyped Cursor Problem nicht nachtesten.
(Ora9.2 verhält sich da nicht so zickig, aber _anders_, außerdem habe ich gerade einen akuten Mangel an Testlaune )
Das Problem ist, dass RefCursor generell weak typed sind. Für Bulk collect braucht du aber einen strong typed Cursor.
Du müsstest nämlich zuerst einen Ref Cursor öffnen und als Bind variable auslesen.
SQL-Code:
begin
  :oCur := TestCurPck.OpenCursor;
/* mit etwas Glück reicht es die Refferenz auf einen StrongTyped Cursor zu verwenden */
end;
Jetzt könnstest du FetchRecs ausführen (solange bis iState = 1).
SQL-Code:
begin
  /* Wenn Ora hinter dem RefCursor den geöffneten StrongTyped Cursor aus dem ersten Statement erkennt ist alles in Butter :) */
  :iState := TestCurPck.FetchRecs(:iCur
                                 ,:iRecLimit
                                 ,:ioTable);
end;
Wie du Objekte (die tbl$F_VBO_DC_OVERVIEW) oder Cursor als Bind variablen verwenden kannst, sollte dir die Doku der CoreLabs-Kompos verraten.

so, das ganze teste ich morgen mal in meiner 9.2-SandBox...

Nachtrag:
Herzlich Willkommen in der Delphi-PRAXIS!
Nur mal nebenbei die TOracleQuery aus DOA ist von sich aus Multithreaded (da sie außerdem einen RefCur kapselt gibt's die Problematik damit nicht )
  Mit Zitat antworten Zitat