Sven's CA-Visual Objects - Seite

23.11.2012

eMail

eMail

Übersicht | Vorheriger | Nächster

Performance OrdKey-Funktionen:

Performance von OrdKeyCount(), ORDKeyNo() und OrdKeyGoto().

Bei Datenbanken < 2000 Records ist das Zeitproblem noch nicht relevant.

Bei großen Datenbanken ist folgendes zu beachten um eine gute Performance zu erhalten:

  1. Kein SetDeleted(TRUE) verwenden
  2. Keine Filter verwenden.
  3. Nach dem Setzen eines Scope unbedingt GOTOP() ausführen, wenn danach als erstes ein ORDKeyNo() aufgerufen wird.
    Bei einem DBSERVER gilt das nur bei Verwendung der ASSIGN's  DBSERBER:OrderTopScope und DBSERVER:OrderBottomScope, da die Methode DBSERVER:OrderScope() am Ende automatisch ein GoTop() ausführt.
  4. Der Scopebereich sollte nicht zu groß sein. < 10000 Datensätze.

Folgende Messungen wurden mit folgendem Versuchsaufbau durchgeführt:

  1. Eine Datenbank mit 52936 Datensätzen.
  2. Davon sind 2139 als gelöscht gekennzeichnet (Deleted() == TRUE)
  3. Es ist ein Index offen, der pro Eintrag 20 Zeichen enthält.
  4. Auf die Datenbank wird über ein Netzwerk zugegriffen und es werden die empfangenen Bytes über den Status-Monitor von Windows-NT gemessen.
  5. Auf dem Client-Rechner werden die identischen Funktionen einmal von einem Clipper 5.3b - Programm und einmal mit einem CAVO 2.5a-1 Programm ausgeführt.
  6. Wenn ein Filter einschaltet ist, so wurde folgender Ausdruck verwendet:
    DBSETFILTER({||! Deleted()},"! Deleted()")
  7. Der verwendete Datenbanktreiber ist in beiden Fällen DBFCDX.

Die Ergebnisse der Messungen:

ausgeführte Funktion gesetzte Filterfunktionen CAVO - empfangene Bytes Clipper - empfangene Bytes
OrdKeyCount() keine 704 kb 704 kb
OrdKeyCount() SetDeleted(TRUE) 712 kb 712 kb
OrdKeyCount() gesetzter Filter 32344 kb 32192 kb
OrdKeyCount() Scope mit  5579 Records 961 kb 960 kb
OrdKeyCount() Scope mit 44416 Records 615 kb 614 kb
OrdKeyGoto(20000) keine 270 kb 269 kb
OrdKeyGoto(20000) SetDeleted(TRUE) 30932 kb 273 kb
OrdKeyGoto(20000) gesetzter Filter 30995 kb 30994 kb
OrdKeyGoto(20000) Scope mit 44416 Records 290 kb 290 kb
OrdKeyGoto(2000) Scope mit  5579 Records 49 kb 48 kb

Die Werte zwischen CAVO und Clipper sind nahezu identisch bis auf das OrdKeyGoto() von CAVO wenn SetDeleted(TRUE) ist.

Im SDK findet man zwei Versionen von OrdKeyGoto. Einmal im Verzeichnis SOURCE\AIM in der Datei DB.PRG folgende Version:

FUNC OrdKeyGoto (nKeyNo)
LOCAL lRetCode AS LOGIC

IF IsNumeric(nKeyNo)
   DBGOTOP()
   DBSKIP(nKeyno -
1)
   lRetCode :=
TRUE
ENDIF

RETURN
lRetCode

und zum Zweiten im Verzeichnis SOURCE\CAVO2RDD in der Datei DB.PRG diese Version:

FUNCTION OrdKeyGoto (nKeyNo)

LOCAL lDeleted AS LOGIC
LOCAL lRetCode AS LOGIC

IF IsNumeric(nKeyNo)
   lDeleted := SetDeleted(FALSE)
   DBGoTop()
   DBSKIP(nKeyno - 1)
   SetDeleted(lDeleted)
   lRetCode := TRUE
ELSE
   ptrErrInfo := _VODBErrInfoPtr()
   MemClear(ptrErrInfo, _SIZEOF(ERRINFO))
   ptrErrInfo.dwGenCode   := EG_ARG
   ptrErrInfo.dwSeverity  := ES_ERROR
   ptrErrInfo.pszArg      := AsPsz(nKeyNo)
   ptrErrInfo.lCanDefault := TRUE
   lRetCode := DoError(#ORDKEYGOTO)
ENDIF

RETURN
lRetCode

Offensichtlich benutzt CAVO 2.5a die erste Version. Diese verhält sich zwar logischer, ist aber nicht kompatibel zur Clipper-Version. Clipper ignoriert den Schalter von SetDeleted() sowohl bei OrdKeyCount() als auch bei OrdKeyGoto(). Dies ist zwar nicht logisch aber wenigsten konsistent. Logisch wäre, wenn OrdKeyCount() bei SetDeleted(TRUE) und keinem Filter das selbe Ergebnis anzeigen würde wie bei SetDeleted(FALSE) und Set Filter to ! Deleted(). Dies ist aber nicht der Fall: Beispiel:

Datenbank mit 10000 Datensätzen, davon sind 2000 Datensätze als gelöscht markiert:

  1. Bei SetDeleted(TRUE) und keinem Filter liefert OrdKeyCount() als Ergebnis 10000.
  2. Bei SetDeleted(FALSE) und Set Filter to ! Deleted() liefert OrdKeyCount() als Ergebnis 8000.

CAVO verhält sich in Bezug auf OrdKeyCount() identisch zu Clipper. Der Bruch bei CAVO kommt erst mit der Funktion OrdKeyGoto(), diese berücksichtigt nämlich den Wert von SetDeleted() im Gegensatz zu Clipper. Dies ist zwar eigentlich logisch richtig aber leider nicht konsistent zum Verhalten von OrdKeyCount() und eben auch nicht kompatibel zu Clipper. Die zweite Version macht OrdKeyCount() quasi Clipper-Kompatibel und verhält sich exakt so wie die Clipper-Version, doch kommt sie leider nicht zum Einsatz.

Aufgrund der oben gemachten Feststellungen wird klar warum ein DataListView mit SetDeleted(TRUE) nicht immer richtig funktionieren kann. Ein DataListView ermittelt bei einem aktiven Index am Anfang und bei jedem Refresh() erstmal mit OrdKeyCount() die Größe der anzuzeigenden Datenbank. Beim Bewegen des Thumb-Buttons wird der erste Datensatz mit OrdKeyGoto() positioniert und der Rest der anzuzeigenden Datensätze wird mit Skip() ermittelt.
Schaut man sich die obige Tabelle an, wird auch klar wieso ein DataListView in manchen Fällen so langsam wird. Hat man so eine Datenbank mit 50000 Datensätzen und hat einen Filter aktiv so werden allein beim ersten Anzeigen des DataListViews mal lässig über 30000000 Bytes sprich 30 MBytes von CAVO geladen. In diesen Fällen verhält sich der DataBrowser günstiger, da er nur mit Skip() und Goto() Befehlen arbeitet - genauso wie das gute alte TBrowse aus Clipper. Man hat natürlich den Nachteil, das sich kein Thumb-Button relativ zur Datenbank positionieren läßt.

Hier die Source der orginal Funktionen aus dem SDK von CAVO 2.5a:

FUNCTION OrdKeyCount (xOrder, cOrdBag)
  RETURN DBORDERINFO(DBOI_KEYCOUNT, cOrdBag, xOrder, NIL)

FUNCTION ORDKeyNo (xOrder, cOrdBag)
   RETURN DBORDERINFO(DBOI_POSITION, cOrdBag, xOrder, NIL)

 

Home | Kontakt | Impressum | ©2012 Ingenieur-Büro Dipl. Ing. Sven Ebert