Große Tabelle in Array einlesen ...

Zugriff, Engines, Konvertierung. Von ADS über DBF bis zu SQL.

Moderator: Moderatoren

Antworten
Benutzeravatar
Wolfgang_B
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 484
Registriert: Do, 14. Jun 2007 18:22
Wohnort: 94065 Waldkirchen
Hat sich bedankt: 14 Mal
Danksagung erhalten: 5 Mal

Große Tabelle in Array einlesen ...

Beitrag von Wolfgang_B »

Mahlzeit ...
ich bin mir nicht sicher, zumindest finde ich im Forum nichts, ob ich die Frage nicht schon gestellt habe, wenn ja -> sorry ...

Ich muß eine große Tabelle (Rechnungen 50.000 Datensätze) für Browse in ein Array einlesen. Ich mache das jetzt mir "DO WHILE ! EOF()" und entsprechenden Filterbedingungen. Das dauert etwa 25 Sek.auf einem lokalen Rechner. Im Netz können es da schon mal 50 Sek werden. Gibts da ne Möglichkeit das schneller zu machen?
Beste Grüße
Wolfgang

Mitglied des Deutschsprachigen Xbase-Entwickler e. V.
Mitglied der XUG Osnabrück
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21165
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 206 Mal
Danksagung erhalten: 67 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Manfred »

auf jeden Fall schon mal auf DbEval() aumstellen. Und was heißt Filterbedingungen? Wirklich Filter? geht es nicht auch über Scope?
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von brandelh »

SET FILTER nicht mit Index mixen ...

Am schnellsten ist

1. Seek auf ersten Treffer, falls das möglich ist, ansonsten ersten möglichen Indextreffer
2. DBEVAL() ... mit REST (sonst fängt er von Anfang an), FOR Bedingung, wenn möglich ENDE Codeblock
3. Wenn möglich muss ein Index die möglichen Treffer stark beschränken
Gruß
Hubert
Benutzeravatar
Tom
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 9345
Registriert: Do, 22. Sep 2005 23:11
Wohnort: Berlin
Hat sich bedankt: 100 Mal
Danksagung erhalten: 359 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von Tom »

Ein SELECT INTO mit einem Array aus DataObjects als Ziel dürfte sehr schnell sein.
Herzlich,
Tom
Benutzeravatar
Wolfgang_B
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 484
Registriert: Do, 14. Jun 2007 18:22
Wohnort: 94065 Waldkirchen
Hat sich bedankt: 14 Mal
Danksagung erhalten: 5 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Wolfgang_B »

erst mal Danke!

ich habe noch vergessen zu sagen, daß ich in der Schleife noch eine Function aufrufe, in der ich für jede Rechnung verschiedene Berechnungen mache. Aus dieser Function bekomme ich ein Array zurück.
Wie müßte denn der Syntax für DbEval sein? Habe ich noch nie verwendet. Aus der Doku werde ich nicht schlau :oops:
Beste Grüße
Wolfgang

Mitglied des Deutschsprachigen Xbase-Entwickler e. V.
Mitglied der XUG Osnabrück
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von Martin Altmann »

Wolfgang,
der einfachste Weg ist:

Code: Alles auswählen

mitglabt->( dbeval( {|| aadd( aAlleAbt, { AID, "  " + strzero( EINTRITTM, 2 ) + "/" + alltrim( str( EINTRITTJ ) ) + iif( AUSTRITTJ > 0, "   " + strzero( AUSTRITTM, 2 ) + "/" + alltrim( str( AUSTRITTJ ) ), "" ), recno() } ), iif( ( AUSTRITTM == 0 ) .and. ( AUSTRITTJ == 0 ), nAnz++, ) } ) )
Da siehst Du auch, wie eine Funktion genutzt werden kann (in meinem Fall liefert sie einen String zurück).
Je nach Menge der Daten (Anzahl Sätze und Felder) kann es schneller sein, das Array vorher in der benötigten Länge anzulegen und dann gezielt zu befüllen:

Code: Alles auswählen

::aMITGLgel := array( 50000 )
nI := 0
mitglied->( DbGoTop() )
mitglied->( dbeval( {|| ::aMITGLgel[ ++nI ] := { MID, alltrim( alltrim( VORNAME ) + " " + alltrim( NAME ) ), GELOESCHT, AKTIVMITGL, alltrim( alltrim( NAME ) + ", " + alltrim( VORNAME ) ) } }, {|| ( .NOT. AKTIVMITGL ) .OR. GELOESCHT } ) )
Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
Wolfgang_B
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 484
Registriert: Do, 14. Jun 2007 18:22
Wohnort: 94065 Waldkirchen
Hat sich bedankt: 14 Mal
Danksagung erhalten: 5 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Wolfgang_B »

vielen Dank. Das hilft mir schon mal weiter ...
Beste Grüße
Wolfgang

Mitglied des Deutschsprachigen Xbase-Entwickler e. V.
Mitglied der XUG Osnabrück
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von brandelh »

Je nach Art der gesuchten Daten kann man mit der richtigen Sortierung viel Zeit sparen.
Das Beispiel von Martin, geht die komplette Datei durch, manchmal muss man das !

Wenn man aber z.B. nur die Adressen in einem Postleitzahlbereich anschreiben will, setzt man den Index auf die Postleitzahl,
DBSEEK() auf den ersten möglichen Treffer
die bWhileCondition ... auf die Abbruchbedingung
und ganz wichtig, den letzten Parameter lRest auf .t.

Code: Alles auswählen

DbEval( <bBlock>, ;
       [<bForCondition>], ;
       [<bWhileCondition>], ;
       [<nCount>], ;
       [<xRecordID>], ;
       [<lRest>]  ) --> NIL
Bei ein paar Tausend Sätzen spielt das auf einer SSD keine Rolle, aber wenn man nur 10% von 500.000 Sätzen durchsuchen muss ist das schon ein Unterschied.

Natürlich sollte man aber auch TOMs Select mal testen (hab ich keine Erfahrung mit),
insbesondere bei dem Durchsuchen der ganzen Datei könnte da viel Potential liegen, wenn man SQL kann und die Umsetzung gut war.

Vor Jahren hatte ich mal einen Vergleich mit DO WHILE ! EOF() und DBEVEAL() mit gleichem Suchbegriff und gleicher Datei war DBEVAL() etwa 1/3 schneller ...
Gruß
Hubert
Benutzeravatar
Wolfgang_B
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 484
Registriert: Do, 14. Jun 2007 18:22
Wohnort: 94065 Waldkirchen
Hat sich bedankt: 14 Mal
Danksagung erhalten: 5 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Wolfgang_B »

So, habe jetzt mal alle Möglichkeiten durchgespielt (außer Tom). Mit Abstand am Schnellsten ist (20 Sek) ist:

Code: Alles auswählen

  IF N1->(DBSEEK(aXbp[4]:getData()))
		DO WHILE ! EOF()
		....
		
			N1->(DBSKIP())
		ENDDO	
Mit 70 Sek. ist DBEVAL() am langsamtsen

Code: Alles auswählen

n1->( DBEVAL ({ || AADD(aARR2, {n1->rech_jahr, n1->rech_nr, ...) } )}, {|| aXbp[4]:getData() == "2020"},,,,.T.))
wobei Index auf Jahr (aXbp[4]:getData())
Beste Grüße
Wolfgang

Mitglied des Deutschsprachigen Xbase-Entwickler e. V.
Mitglied der XUG Osnabrück
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21165
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 206 Mal
Danksagung erhalten: 67 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Manfred »

janu,
hast Du mal geprüft, wieviel Sätze Du mit dem Dbseek() überspringst, die DBEval zusätzlich durchlaufen mußt? Ich sehe nämich nirgendwo, dass Du da auch ein Dbseek vorher machst. Du sagst zwar schön es soll nur den rest machen, aber am Anfang stehend ist alles folgende der rest.
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von brandelh »

Bei Gelegenheit probiere ich das mal MIT Tom durch ... ich kanns nicht so recht glauben, dass DBEVAL() langsamer ist, wenn beide die gleiche Arbeit haben (besonders interne Funktionsaufrufe und Array Zuweisungen)
Gruß
Hubert
Benutzeravatar
Wolfgang_B
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 484
Registriert: Do, 14. Jun 2007 18:22
Wohnort: 94065 Waldkirchen
Hat sich bedankt: 14 Mal
Danksagung erhalten: 5 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Wolfgang_B »

Hast recht. Wird aber deswegen auch nicht schneller als DO WHILE !EOF() mit Index und DBSEEK() auf den ersten Satz. Problem ist auch, daß ich bei jedem Satz mehrere Werte per Funktion berechnen muß, die in einem Array zurückgegeben werden und dann in das erste Array mit einfliesen. Ich wüßte nicht, wie ich diese Logik mit DBEVAL() realisieren könnte.

So z.B.

Code: Alles auswählen

DBSEEk(..)
Do While ! eof()  
   aArray := Funktion(berechne)
   IF aArray[1] > 0
		AADD(aArray2 ( x1,x2, aArray[1], aArray[2], aArray[3], ...)
	ENDIF
	DBSKIP()
ENDDO	
Beste Grüße
Wolfgang

Mitglied des Deutschsprachigen Xbase-Entwickler e. V.
Mitglied der XUG Osnabrück
Benutzeravatar
Manfred
Foren-Administrator
Foren-Administrator
Beiträge: 21165
Registriert: Di, 29. Nov 2005 16:58
Wohnort: Kreis Wesel
Hat sich bedankt: 206 Mal
Danksagung erhalten: 67 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Manfred »

Code: Alles auswählen

Dbseek()
DbEval({|| aArray := Funktion(berechne),IF(aArray[1]>0,AADD(aArray2 ( x1,x2, aArray[1], aArray[2], aArray[3], ...),NIL)},,,,.T.)
So aus der Hüfte geschossen....
Gruß Manfred
Mitglied der XUG Osnabrück
Schatzmeister des Deutschsprachige Xbase-Entwickler e.V.
großer Fan des Xbaseentwicklerwiki https://wiki.xbaseentwickler.de/index.p ... Hauptseite
Doof kann man sein, man muß sich nur zu helfen wissen!!
Benutzeravatar
Wolfgang_B
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 484
Registriert: Do, 14. Jun 2007 18:22
Wohnort: 94065 Waldkirchen
Hat sich bedankt: 14 Mal
Danksagung erhalten: 5 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von Wolfgang_B »

Manfred, funktioniert. Aber insgesamt nicht wesentlich schneller als mit DO WHILE ...

An alle Danke!
Beste Grüße
Wolfgang

Mitglied des Deutschsprachigen Xbase-Entwickler e. V.
Mitglied der XUG Osnabrück
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von Martin Altmann »

Wolfgang,
hast du mal versucht, das Array vorab in der benötigten Größe anzulegen und in DbEval() nicht mit Aadd() zu arbeiten?

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von brandelh »

DBEVAL() kann nur schneller sein weil sie intern bessere Methoden für den Schleifendurchlauf haben (optimierter C-Code),
wenn aber die Berechnungen selbst etwas dauern, kann das so viel mehr Zeit kosten, dass der minimale Vorteil aufgebraucht wird.

Es kommt natürlich auch auf verständlichen Code an und da ziehe ich oft das langsamere do while einer komplexen DBEVAL() Zeile vor ...
Hauptsache es ist schnell genug :D
Gruß
Hubert
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Große Tabelle in Array einlesen ...

Beitrag von AUGE_OHR »

Wolfgang_B hat geschrieben: Mo, 14. Dez 2020 12:08 So, habe jetzt mal alle Möglichkeiten durchgespielt (außer Tom). Mit Abstand am Schnellsten ist (20 Sek) ist:
...
wobei Index auf Jahr (aXbp[4]:getData())
wie viele Datensätze hast du das du 20 Sec. brauchst :shock:

Code: Alles auswählen

IF N1->(DBSEEK(aXbp[4]:getData()))

{|| aXbp[4]:getData() == "2020"}

du gibst ein Jahr als "Bedingung vor" und hast den Index auf also würde ich ein SCOPE verwenden.
damit werden nur die betreffende Daten geSKIPt

---

sollte der Begriff "im" Text Feld stehen kann man OrdWildSeek() verwenden
gruss by OHR
Jimmy
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14641
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 87 Mal
Kontaktdaten:

Re: Große Tabelle in Array einlesen ...

Beitrag von Jan »

Jimmy,
Wolfgang_B hat geschrieben: So, 13. Dez 2020 12:04Ich muß eine große Tabelle (Rechnungen 50.000 Datensätze) für Browse in ein Array einlesen.
Und er erwähnte, das da auch noch Berechnungen zu jedem Satz gehören.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Antworten