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
)