Ich hab folgendes, seltsames, Problem.
Ich importiere Daten in Access Tabellen, diese Tabellen existieren
schon, werden aber beim Start gelöscht (DROP TABLE) und anschließend
wieder mit den neuen Daten erzeugt.
Ich lade diese Tabellen in DAO Recordsets, mit diesen Recordsets stelle
ich Berechnungen an, dazu suche ich Einträge, gehe sie mit while
Schleifen durch etc.
Mit den berechneten Werten wird eine Tabelle generiert und anschließend
ein Bericht geöffnet der die generierte Tabelle als Grundlage hat.
Jetzt habe ich das Problem das das Endergebnis, wenn ich die Funktion
über einen Button im Formular starte, anderes ist als wenn ich die ganze
Funktion mit dem Debuger Schritt für Schritt durchgehe. Ich setze z.B.
einen Haltepunkt beim Button und gehe alles Schritt für Schritt mit F8
durch.
Es müsste doch genau dasselbe rauskommen weil ja nichts anderes passiert
außer das ich alles langsam durch gehe??
MFG
Stefan Schmidhammer
Stefan Schmidhammer wrote:
Was genau ist denn anders?
Gruß
Stefan Schmidhammer <sst...@web.de> schrieb:
so ganz ohne Deinen Code zu kennen fällt es schwer, das Problem zu
analysieren.
Du könntest Deinem Code ein paar "DoEvents" beifügen. Das macht die
Verarbeitung zwar langsamer - aber vielleicht hilft das ja.
Wenn Du dann immer noch Probleme hast solltest Du uns den relevanten Code
posten.
Du schreibst oben, dass Du eine Tabelle generierst, die als Datenquelle für
den Bericht dient. Sind dort die Datensätze schon unterschiedlich?
Wahrscheinlich ja.
Sind es immer die selben DS, die fehlen? Lässt sich daraus etwas schliessen?
CU
--
Thomas
Homepage: www.Team-Moeller.de
TM-ÄnderungsProtokoll: Update auf Version 2.25 (seit 12.08.05)
Groß- u. Kleinschreibung wird bei Änderungen berücksichtigt.
Hallo,
Der Code besteht aus mehr als 1000 Zeilen und ist eine Monatsabrechnung,
ich will den Code hier ehrlich gesagt nicht online stellen ...
Aber es Funktioniert im Prinzip so ich es geschrieben hab. Es sind auch
keine besonderen Dinge im Code vorhanden. Die verschiedenen Recordsets
laufen durch ein paar Schleifen und es wird in den Recordsets gesucht.
Dazu werden auch manchmal Bookmarks gesetzt. Mit ein paar Werten der
Recordsets wird gerechnet und das Ergebnis wird in die Ergebnis-Tabelle
geschrieben.
Es werden 7 Tabellen, die schon existieren und alte Daten beinhalten,
geleert und neu befüllt. Diese 7 Tabellen haben bei der normalen
Ausführung und bei der Debug Ausführung denselben Inhalt, an den Daten
kann es also auch nicht liegen, es muss der VBA Code sein der damit rechnet.
Ja die Ergebnis-Tabelle enthält unterschiedliche Daten, genauergesagt
sind meistens 3-5 Datensätze unterschiedlich, ein System konnte ich
bisher keines entdecken aber es sind immer die gleichen. Man kann den
Bericht selbst also schonmal als Fehlerursache ausschließen da die Daten
in der Tabelle anders sind.
Es ist ziemlich frustrierend weil ich schon länger an dem Problem sitze
und auch nur Raten kann was die Ursache ist weils mit dem Debug Modus ja
funktioniert :-/
MFG
Stefan Schmidhammer
Stefan Schmidhammer schrieb:
> Der Code besteht aus mehr als 1000 Zeilen und ist eine Monatsabrechnung,
> ich will den Code hier ehrlich gesagt nicht online stellen ...
und 1000 Zeilen Quellcode will hier wahrscheinlich auch niemand lesen.
Glaskugelmodus: es wäre evtl. sinnvoller, statt einer einzigen
1000-zeiligen Routine entsprechend mehr kleine - und daher besser
prüfbare - Routinen zu programmieren.
> Es werden 7 Tabellen, die schon existieren und alte Daten beinhalten,
> geleert und neu befüllt. Diese 7 Tabellen haben bei der normalen
> Ausführung und bei der Debug Ausführung denselben Inhalt, an den Daten
> kann es also auch nicht liegen,
Das ist doch schon mal ein wichtiger Ansatz. Das Ausgangsdatenmaterial
ist also korrekt.
> es muss der VBA Code sein der damit
> rechnet.
Dann bau doch an den Berechnungsstellen mal ein Debug.Print mit den
Variablen ein und lass den Code durchlaufen. Das Ergebnis könnte Dir ja
Aufschluss geben.
Es wäre sicher auch möglich, zur Eingrenzung des Problems Teile des
Codes auszukommentieren (FAQ 6.13 Lösung 2) oder per bedingter
Kompilierung aus der Ausführung rauszunehmen. Auch das könnte einen
gewissen Erkenntnisgewinn verschaffen. Wenn möglich, evtl. mal Tabelle
nach Tabelle einzeln abarbeiten lassen und das Berechnungsergebnis
prüfen. Statt sieben Schleifendurchläufen nur einen, zwei, drei ...
Interessant wäre auch, *wie* Du debuggst. Einfach mal
Einzelschrittmodus? Haltepunkte? MsgBox? Benutzung des
Überwachungsfensters? Wenn ja: welche Art von Überwachung?
> Ja die Ergebnis-Tabelle enthält unterschiedliche Daten, genauergesagt
> sind meistens 3-5 Datensätze unterschiedlich, ein System konnte ich
> bisher keines entdecken aber es sind immer die gleichen.
Das muss unsereins nun aber nicht verstehen: "kein System, aber immer
die gleichen"?!
Dass wir uns hier nicht mit irgendwelchen Timern in Deinem Formular
rumschlagen müssen, setze ich jetzt einfach mal voraus. Sowas macht
nämlich ggf. richtig Ärger.
Zusatzhinweise: Falls in den Berechnungen (Monatsabrechnungen!) mit
Datums- und Zeitangaben gerechnet wird, ist zu beachten, dass es sich
intern um den Datentyp Double handelt, also sind Rundungsdifferenzen auf
Grund der Gleitkommazahlen nicht auszuschließen. Dito beim Rechnen
und/oder Runden von Beträgen.
Abweichungen zu händisch ausgerechneten Werten ergeben sich evtl. auch
aus leeren Feldinhalten (Null), z.B. bei der Ermittlung von Anzahl oder
Mittelwert.
Im übrigen rächt sich an dieser Stelle ein häufiges Vergehen: nämlich
bei der SW-Entwicklung nicht von Anfang an Testszenarien (mit
entsprechenden Testdaten) mitgedacht zu haben. Also: Testplan erstellen
und dann systematisch abarbeiten.
mfg,
Michel
Michel Fouquet <MaPou...@wanadoo.fr> schrieb:
> Interessant wäre auch, *wie* Du debuggst. Einfach mal
> Einzelschrittmodus? Haltepunkte? MsgBox? Benutzung des
> Überwachungsfensters? Wenn ja: welche Art von Überwachung?
Das hatte er geschrieben: Haltepunkt und Einzelschrittmodus.
> Zusatzhinweise: Falls in den Berechnungen (Monatsabrechnungen!) mit
> Datums- und Zeitangaben gerechnet wird, ist zu beachten, dass es
> sich intern um den Datentyp Double handelt, also sind Rundungs-
> differenzen auf Grund der Gleitkommazahlen nicht auszuschließen.
> Dito beim Rechnen und/oder Runden von Beträgen.
Grundsätzlich hast Du Recht. Aber bei Ausführung mit und ohne
Einzelschrittmodus wäre der Fehler immer der selbe. Das ist es also nicht.
> Abweichungen zu händisch ausgerechneten Werten ergeben sich evtl.
> auch aus leeren Feldinhalten (Null), z.B. bei der Ermittlung von
> Anzahl oder Mittelwert.
Auch dieser Hinweis ist generell richtig. Die Differenzen ergeben sich aber
bei der Ausführung des Codes abhängig davon ob mit oder ohne
Einzelschrittmodus ausgeführt wird.
Stefan Schmidhammer <sst...@web.de> schrieb:
>> so ganz ohne Deinen Code zu kennen fällt es schwer, das Problem zu
>> analysieren.
>> Du könntest Deinem Code ein paar "DoEvents" beifügen. Das macht die
>> Verarbeitung zwar langsamer - aber vielleicht hilft das ja.
Hast Du mal ein paar "DoEvents" eingefügt?
Hat sich dadurch etwas geändert?
>> Wenn Du dann immer noch Probleme hast solltest Du uns den
>> relevanten Code posten.
> Der Code besteht aus mehr als 1000 Zeilen und ist eine Monats-
> abrechnung, ich will den Code hier ehrlich gesagt nicht
> online stellen ...
Deshalb schrieb ich von den *relevanten* Stellen. Aber ich gebe zu, dass es
bei 1000 Zeilen und dieser Problemlage schwierig ist, diese zu
identifizieren.
> Aber es Funktioniert im Prinzip so ich es geschrieben hab. Es sind
> auch keine besonderen Dinge im Code vorhanden. Die verschiedenen
> Recordsets laufen durch ein paar Schleifen und es wird in den
> Recordsets gesucht.
Bau mal in diese Schleifen ein "DoEvents" ein. Das wird den Code
verlangsamen. Das tut der Einzelschrittmodus auch.
Wenn sich dadurch etwas ändert baust Du ein "DoEvents" nach dem anderen
wieder aus. So finden wir die Stelle, an der eine Änderung erforderlich ist.
> Dazu werden auch manchmal Bookmarks gesetzt. Mit ein paar Werten der
> Recordsets wird gerechnet und das Ergebnis wird in die
> Ergebnis-Tabelle geschrieben.
> Es werden 7 Tabellen, die schon existieren und alte Daten beinhalten,
> geleert und neu befüllt. Diese 7 Tabellen haben bei der
> normalen Ausführung und bei der Debug Ausführung denselben Inhalt, an den
> Daten kann es also auch nicht liegen, es muss der VBA Code
> sein der damit rechnet.
Damit haben wir schon einmal eine erste Erkenntnis. Der Code, der diese
Tabellen befüllt, scheint nicht die Quelle Deiner Probleme zu sein.
Meine obigen Tipps beziehen sich also nur auf den noch folgenden Code.
> Ja die Ergebnis-Tabelle enthält unterschiedliche Daten,
Ich glaube, Du musst das Verfahren, mit dem Du Deine Daten bearbeitest
nochmal genauer beschreiben:
- Du kopierst Daten in 7 Tabellen
- Dann wird irgendwie gerechnet und die Daten kommen in die Ergebnistabelle.
Hier ergeben sich Unterschiede.
- Dann wird ein Bericht auf Basis der Daten in der Ergebnistabelle
angezeigt.
Ist das so richtig?
> genauergesagt sind meistens 3-5 Datensätze unterschiedlich, ein
> System konnte ich bisher keines entdecken aber es sind immer die gleichen.
Diesen Satz hat Michel schon moniert. Ich verstehe ihn auch nicht.
Ist die Anzahl der Datensätze immer gleich?
Gibt es 3 bis 5 DS, die unterschiedliche Werte aufweisen?
Sind diese Werte dann immer gleich?
> Man kann den Bericht selbst also schonmal als Fehlerursache
> ausschließen da die Daten in der Tabelle anders sind.
Das sehe ich genau so.
> Es ist ziemlich frustrierend weil ich schon länger an dem Problem
> sitze und auch nur Raten kann was die Ursache ist weils mit dem
> Debug Modus ja funktioniert :-/
Ich denke, wenn Du nochmals Dein vorgehen Stück für Stück beschreibst, uns
dann sagst an welcher Stelle Unterschiede auftreten, dort in den Code
DoEvents einfügst oder uns evtl. die relevanten Codestellen postest werden
wir schon weiter kommen.
Thomas Möller schrieb:
>> Interessant wäre auch, *wie* Du debuggst. Einfach mal
>> Einzelschrittmodus? Haltepunkte? MsgBox? Benutzung des
>> Überwachungsfensters? Wenn ja: welche Art von Überwachung?
>
> Das hatte er geschrieben: Haltepunkt und Einzelschrittmodus.
ja, das stand so im OP. Mein Hinweis war, offensichtlich
missverständlich, als Frage getarnt: nämlich dass es ausser Haltepunkt
und F8 noch eine Reihe weiterer Möglichkeiten des Debuggens gibt.
Lokalfenster und Überwachungsfenster finden nach meiner Beobachtung viel
zu selten Verwendung.
> Grundsätzlich hast Du Recht.
Natürlich! :-)
> Aber bei Ausführung mit und ohne
> Einzelschrittmodus wäre der Fehler immer der selbe. Das ist es also nicht.
ACK - es war ja auch ausdrücklich als "Zusatzhinweis" gekennzeichnet.
Wie es nun mal meine etwas abschweifende Art ist ... Es war hier eher
für die Lurker gedacht: alle anderen möglichen Fehlerquellen müssen
natürlich vorher ausgeschaltet sein.
mfg,
Michel
Stefan Schmidhammer schrieb:
> Es müsste doch genau dasselbe rauskommen weil ja nichts anderes passiert
> außer das ich alles langsam durch gehe??
Nein.
Die Sache mit den DoEvents löst es schon?
Wenn nicht:
- DoCmd.RunSQL ersetzen durch CurrentDbC.Execute
- Recordset.Close und Set Recordset = Nothing verwenden
- das DROP TABLE ersetzen durch DELETE FROM TABLE
- falls Datumsbezüge mittels Now(), Date() oder Time() in SQLs erfolgen,
diese auslagern
- DFirst und DLast nicht verwenden
- JetComp.exe anwenden
mfG
--> stefan <--
--
Access-FAQ http://www.donkarl.com/
KnowHow.mdb http://www.freeaccess.de
Newbie-Info http://www.doerbandt.de/Access/Newbie.htm
Michel Fouquet wrote:
> Thomas Möller schrieb:
>
>>> Interessant wäre auch, *wie* Du debuggst. Einfach mal
>>> Einzelschrittmodus? Haltepunkte? MsgBox? Benutzung des
>>> Überwachungsfensters? Wenn ja: welche Art von Überwachung?
>>
>> Das hatte er geschrieben: Haltepunkt und Einzelschrittmodus.
>
> ja, das stand so im OP. Mein Hinweis war, offensichtlich
> missverständlich, als Frage getarnt: nämlich dass es ausser Haltepunkt
> und F8 noch eine Reihe weiterer Möglichkeiten des Debuggens gibt.
> Lokalfenster und Überwachungsfenster finden nach meiner Beobachtung viel
> zu selten Verwendung.
Das liegt wohl daran, dass man landlaeufig unter Debugging nicht mehr den
Fachbegriff der Entlausung / des Kammerjagens sieht, sondern die
schrittweise Ausfuehrung von Programmcode, die eigentlich eine Untermenge
des Debugging darstellt.
>> Grundsätzlich hast Du Recht.
>
> Natürlich! :-)
Sehe ich auch so. ;-)
Gruss - Peter
Hab ein paar Korinthen gefunden ;-)
stefan hoffmann wrote:
> Stefan Schmidhammer schrieb:
>> Es müsste doch genau dasselbe rauskommen weil ja nichts anderes passiert
>> außer das ich alles langsam durch gehe??
> Nein.
>
> Die Sache mit den DoEvents löst es schon?
>
> Wenn nicht:
> - DoCmd.RunSQL ersetzen durch CurrentDbC.Execute
> - Recordset.Close und Set Recordset = Nothing verwenden
> - das DROP TABLE ersetzen durch DELETE FROM TABLE
^^^^^ ^^^^^
Der ungeuebte Leser koennte die Schreibweise misverstehen. Besser so:
DROP TABLE <Tabellenname> ... DELETE FROM <Tabellenname>
> - falls Datumsbezüge mittels Now(), Date() oder Time() in SQLs erfolgen,
> diese auslagern
Wie meinst du das?
> - DFirst und DLast nicht verwenden
Und auch kein DSum/DMin..., also gar keine Domain-Funktionen, sondern
bestenfalls Ersatzfunktionen.
Gruss - Peter
--
Ich beantworte keine Fragen per Email.
Mitglied im http://www.dbdev.org
FAQ: http://www.donkarl.com
stefan hoffmann schrieb:
> - das DROP TABLE ersetzen durch DELETE FROM TABLE
und ich habe mal, was das Löschen von Tabelleninhalten betrifft, genau
das Gegenteil gelernt. Sofern *alle* DS gelöscht werden sollen, ist es
performanter, das DROP TABLE-Statement zu verwenden.
(Was das Aufblähen der MDB betrifft, dürften sich vermutlich beide
nichts nehmen, habe ich allerdings nicht nachgeprüft. Das würde Paul
Rohorzka wahrscheinlich nicht einfach so durchgehen lassen.)
Streiten könnte man sich wahrscheinlich darüber, ob DROP und CREATE
zusammen immer noch schneller sind als DELETE. Das folgende INSERT gilt
ja dann für beide.
Das vom OP beschriebene Problem liegt allerdings, so wie ich es bisher
verstanden habe, nicht am Löschen der Daten bzw. Tabellen, sondern
irgendwo im Verlauf der Rekonstruktion bzw. des (erneuten) Befüllens der
Tabellen.
Zudem geht nicht der *komplette* Vorgang in die Hose. Sonst könnte man
vermuten, dass das System mit dem Löschen der Tabelle(n) vielleicht noch
nicht fertig ist, wenn es bereits mit dem Erzeugen und Befüllen beginnen
will.
Das DELETE FROM <table> ist da aber noch langsamer und in *diesem* Fall
könnte ich mir eher vorstellen, dass noch nicht alle DS gelöscht sind,
aber bereits neue geschrieben werden.
Sollte die Verwendung des DELETE FROM-Statements aber aus genau diesen
Gründen (Verlangsamung der Programmausführung) von Dir vorgeschlagen
worden sein?
Ratlos,
Michel
Ein Gedanke:
Ich importiere die Tabellen, dazu erstelle ich eine Struktur mit
TableDef und nachdem die Struktur angelegt wurde werden die Datensätze
mit INSERT's eingefügt. Danach lese ich diese Tabellen in Recordsets
ein. Kann es sein das ACCESS intern noch gar nicht mit den ganzen INSERT
Anweisungen fertig ist wenn ich schon die Tabellen in die Recordsets
einfüge? Und wenn ich alles langsam im Debug Modus durchgehe passiert
das nicht da ACCESS genug Zeit hat?
> - DoCmd.RunSQL ersetzen durch CurrentDbC.Execute
Ich verwende in der MDB nur CurrentDB.execute()
Das DoCmd.RunSQL() hab ich bis jetzt nur in ADP's mit SQL-Server
verwendet, wusste gar nicht das das auch in MDB's geht
> - Recordset.Close und Set Recordset = Nothing verwenden
Hab ich jetzt überall am Ende eingefügt, das hatte ich vorher nicht
> - das DROP TABLE ersetzen durch DELETE FROM TABLE
Wegen der Diskussion was jetzt besser ist, DELETE oder DROP.
Soweit ich weiß sollte man DELETE verwenden wenn man bestimmte
Datensätze löschen will, hier kann man ja auch Kriterien angeben, dabei
wird immer ein Datensatz nach dem anderen gelöscht, also falls man die
ganze Tabelle leeren will kann das dauern weil jeder Satz einzeln
gelöscht wird.
Um eine ganze Tabelle zu leeren hab ich immer TRUNCATE verwendet, hier
bleibt die Struktur erhalten, die Daten werden einfach weggeworfen.
Um die komplette Tabelle mit Struktur zu löschen verwende ich immer DROP
> - falls Datumsbezüge mittels Now(), Date() oder Time() in SQLs erfolgen,
> diese auslagern
Kommt nicht vor
> - DFirst und DLast nicht verwenden
Ich verwende an einigen Stellen DLookup()
Ich werd hier mal Debug Ausgaben einfügen
> - JetComp.exe anwenden
Habs eben auf der MS Seite gefunden, ist das dasselbe wie unter "Extras
-> Datenbank-Dienstprogramme -> DB komprimieren und reparieren" ?
MFG
Stefan
> Hast Du mal ein paar "DoEvents" eingefügt?
> Hat sich dadurch etwas geändert?
Ja, es scheint jetzt zu funktionieren. Siehe dazu auch meine andere
Antwort zu stefan hoffmann's Beitrag.
> Ich glaube, Du musst das Verfahren, mit dem Du Deine Daten bearbeitest
> nochmal genauer beschreiben:
> - Du kopierst Daten in 7 Tabellen
> - Dann wird irgendwie gerechnet und die Daten kommen in die
> Ergebnistabelle. Hier ergeben sich Unterschiede.
> - Dann wird ein Bericht auf Basis der Daten in der Ergebnistabelle
> angezeigt.
> Ist das so richtig?
Korrekt.
Hier ist der Teil des Codes der anscheinend anders ausgeführt wird,
dieser Code kommt mehrfach vor ist aber bis auf kleine Unterschiede
immer derselbe. Das ganze passiert in einer While Schleife (Do While Not
R1.EOF)
...
weiter = R1.Bookmark
'vorgemerkten Datensatz anwählen und Gebühr eintragen
R1.Bookmark = vorgemerkt
aktDS = R1![DiätenposID]
'entsprechende Diätenkategorie auswählen
Typ = "Diätenkategorie = '" & R1![Diätenkategorie] & "'"
R2.FindFirst Typ
Nachtgeb = R2![Nächtigung]
x = CSng(dlookup("[NG]", "[tbl_MD]", "[DiätenposID] = " & aktDS))
x = x + Nachtgeb
dbs.Execute ("UPDATE [tbl_MD] SET NG = '" & x & "' WHERE [DiätenposID] =
" & aktDS), dbFailOnError
Dauer = 0 'Vormerkung löschen
vorgemerkt = ""
vgmNacht = -1
'wieder auf zuletzt bearbeitetem Datensatz positionieren
R1.Bookmark = weiter
...
> Diesen Satz hat Michel schon moniert. Ich verstehe ihn auch nicht.
>
> Ist die Anzahl der Datensätze immer gleich?
> Gibt es 3 bis 5 DS, die unterschiedliche Werte aufweisen?
> Sind diese Werte dann immer gleich?
Das meinte ich so, Wenn ich z.B. die Monatsabrechnung für März 2005
mache dann unterscheiden sich 3 Datensätze. Beim "normalem" Ablauf des
Codes sind es immer die gleichen 3 Datensätze die fehlerhaft sind, auch
die falschen Werte sind immer dieselben. z.B. bei einem Eintrag kommen
immer 15 Euro mehr raus als wenn ich das ganze mit dem Debugmodus durchgehe.
MFG
Stefan
Stefan Schmidhammer schrieb:
> Ein Gedanke:
> Ich importiere die Tabellen, dazu erstelle ich eine Struktur mit
> TableDef und nachdem die Struktur angelegt wurde werden die Datensätze
> mit INSERT's eingefügt. Danach lese ich diese Tabellen in Recordsets
> ein. Kann es sein das ACCESS intern noch gar nicht mit den ganzen INSERT
> Anweisungen fertig ist wenn ich schon die Tabellen in die Recordsets
> einfüge? Und wenn ich alles langsam im Debug Modus durchgehe passiert
> das nicht da ACCESS genug Zeit hat?
ich hatte heute nachmittag zunächst etwas geschrieben, es aber dann doch
wieder weggelöscht, weil ich mir gedacht habe: Du arbeitest beim Löschen
mit SQL-Statements, also wirst Du wohl auch das Anlegen der Tabellen und
deren Befüllung per SQL erledigen.
Da Du nun aber von TableDefs schreibst, nehme ich meine Überlegung von
heute nachmittag doch noch einmal auf. Würde es ggf. helfen, nach dem
Anlegen ein TableDefs.Refresh einzufügen?
<zitat OH>
Eine Auflistung wird mit Objekten gefüllt, wenn zum ersten Mal darauf
zugegriffen wird. Sie wird aber nicht automatisch aktualisiert, um durch
andere Benutzer vorgenommene Änderungen widerzuspiegeln. Wenn anzunehmen
ist, daß eine Auflistung durch einen anderen Benutzer geändert wurde,
rufen Sie die Refresh-Methode für die Auflistung auf, unmittelbar bevor
Sie eine Operation in Ihrer Anwendung durchführen, die das Vorhandensein
oder Fehlen eines bestimmten Objekts in der Auflistung erwartet. Dadurch
sorgen Sie dafür, daß die Auflistung immer möglichst aktuell ist.
Andererseits kann die Verwendung der Refresh-Methode unnötigerweise das
Leistungsverhalten verschlechtern.
</zitat>
mfg,
Michel
Stefan Schmidhammer wrote:
...
>
> Ich verwende in der MDB nur CurrentDB.execute()
> Das DoCmd.RunSQL() hab ich bis jetzt nur in ADP's mit SQL-Server
> verwendet, wusste gar nicht das das auch in MDB's geht
>
...
>
>> - DFirst und DLast nicht verwenden
>
> Ich verwende an einigen Stellen DLookup()
> Ich werd hier mal Debug Ausgaben einfügen
>
...
> MFG
> Stefan
wenn DoEvents etwas brint, würde ich vermuten, daß das Arbeiten mit
verschiedenen Bibliotheken das Problem ist. Beschränke dich also beim
Programmablauf auf eine davon, und dann ist das Problem vielleicht
erledigt.
Gruß
Daniel
Stefan Schmidhammer <sst...@web.de> schrieb:
>> Hast Du mal ein paar "DoEvents" eingefügt?
>> Hat sich dadurch etwas geändert?
> Ja, es scheint jetzt zu funktionieren.
Schön! Wir sind ein Stück weiter gekommen.
>> Ich glaube, Du musst das Verfahren, mit dem Du Deine Daten
>> bearbeitest nochmal genauer beschreiben:
>> - Du kopierst Daten in 7 Tabellen
>> - Dann wird irgendwie gerechnet und die Daten kommen in die
>> Ergebnistabelle. Hier ergeben sich Unterschiede.
>> - Dann wird ein Bericht auf Basis der Daten in der Ergebnistabelle
>> angezeigt.
>> Ist das so richtig?
> Korrekt.
An welchen Stellen hast Du jetzt die DoEvents eingefügt?
Ich würde jetzt wie folgt vorgehen:
Der Teil des Code, in dem die Daten in die 7 Tabellen kopiert werden, ist in
Ordnung? Dann brauchen wir diesen nicht mehr betrachten. Dort kannst Du die
DoEvents entfernen.
Jetzt müssen wir uns den Teil anschauen, der die Berechnungen vornimmt. Kann
man diesen Teil in mehrere logische Blöcke unterteilen?
Sicherlich. Dann würde ich mir jetzt den ersten Block hernehmen und dort die
DoEvents entfernen. Danach intensiv testen. Wenn die Ergebnisse mit und ohne
Einzelschrittmodus identisch sind ist dieser Block o.K.. Dann weiter zum
nächsten Block. Dass machst Du so lange, bis Du einen Block identifiziert
hast, bei dem es auf die DoEvents ankommt. Diesen schaust Du Dir an. Wenn
Dir nicht einfällt, dann meldest Du Dich wieder hier ;-)
> Hier ist der Teil des Codes der anscheinend anders ausgeführt wird,
> dieser Code kommt mehrfach vor ist aber bis auf kleine Unterschiede
> immer derselbe. Das ganze passiert in einer While Schleife (Do While
> Not R1.EOF)
Randbemerkung: "Do Until R1.EOF" ist schneller.
> ...
> weiter = R1.Bookmark
> 'vorgemerkten Datensatz anwählen und Gebühr eintragen
> R1.Bookmark = vorgemerkt
> aktDS = R1![DiätenposID]
> 'entsprechende Diätenkategorie auswählen
> Typ = "Diätenkategorie = '" & R1![Diätenkategorie] & "'"
> R2.FindFirst Typ
> Nachtgeb = R2![Nächtigung]
> x = CSng(dlookup("[NG]", "[tbl_MD]", "[DiätenposID] = " & aktDS))
> x = x + Nachtgeb
> dbs.Execute ("UPDATE [tbl_MD] SET NG = '" & x & "' WHERE
> [DiätenposID] = " & aktDS), dbFailOnError
> Dauer = 0 'Vormerkung löschen
> vorgemerkt = ""
> vgmNacht = -1
> 'wieder auf zuletzt bearbeitetem Datensatz positionieren
> R1.Bookmark = weiter
> ...
Daran fällt mir jetzt nur die Zeile mit dem >>dbs.Execute<< auf. Hat dieses
Statement Auswirkungen auf die Tabelle, die Du gerade offen hast?
>> Diesen Satz hat Michel schon moniert. Ich verstehe ihn auch nicht.
>>
>> Ist die Anzahl der Datensätze immer gleich?
>> Gibt es 3 bis 5 DS, die unterschiedliche Werte aufweisen?
>> Sind diese Werte dann immer gleich?
> Das meinte ich so, Wenn ich z.B. die Monatsabrechnung für März 2005
> mache dann unterscheiden sich 3 Datensätze. Beim "normalem" Ablauf des
> Codes sind es immer die gleichen 3 Datensätze die fehlerhaft sind,
> auch die falschen Werte sind immer dieselben. z.B. bei einem Eintrag
> kommen
> immer 15 Euro mehr raus als wenn ich das ganze mit dem Debugmodus
> durchgehe.
Ich glaube, dass man durch Analyse der Datensätze und der Stellen, an denen
dort die Berechnungen durchgeführt werden, auf die Ursache kommen kann. Das
kann aber eine sehr komplexe Angelegenheit werden. Von daher sollten wir uns
auf das systematische Entfernen der "DoEvents" konzentrieren um den Fehler
einzugrenzen.
CU
Stefan Schmidhammer <sst...@web.de> schrieb:
> Hier ist der Teil des Codes der anscheinend anders ausgeführt wird,
> dieser Code kommt mehrfach vor ist aber bis auf kleine Unterschiede
> immer derselbe.
Kleiner Nachtrag:
Dieser Code gehört in eine Sub ausgelagert. Der "kleine Unterschied" sollte
dort als Parameter übergeben werden. Das macht den Code schlanker, erhöht
somit die Übersichtlichkeit und vereinfacht die Wartung.
Thomas Möller:
> > Das ganze passiert in einer While Schleife (Do While Not
> > R1.EOF)
>
> Randbemerkung: "Do Until R1.EOF" ist schneller.
Theoretisch ja. Praktisch konnte ich keinen Unterschied
feststellen, der nicht von der Streuung innerhalb einer
Methode übertroffen worden wäre.
Eine Erklärung könnte sein, daß der Compiler/Interpreter
Until <Bedingung> und While Not <Bedingung> schlicht
gleich übersetzt. Dann gäbe es noch nicht einmal mehr
theoretisch einen Unterschied.
Wenn man die datensatzweise Abarbeitung eines Recordsets
merkbar beschleunigen will, sollte man auf das
Do-Loop-Konstrukt völlig verzichten und stattdessen
rs.MoveLast
n = rs.RecordCount
rs.MoveFirst
For i = 1 To n
rs.MoveNext
Next i
benutzen. Trotz des i. d. R. erforderlichen MoveLast schlägt
der Geschwindigkeitsvorteil von For-Next gegen Do-Loop
immer noch durch. Je nach Recordsetgröße in der
Größenordnung 10% - 20%.
Gruß aus Mainz
Michael
"Michael Zimmermann" <Zimme...@SZWeb.de> schrieb im Newsbeitrag
news:4364de30$0$21960$9b4e...@newsread2.arcor-online.net...
Sicherlich, wenn man das Recordset DS für DS durchläuft.
Trifft das auch noch zu, wenn man mit .MovePrivious .MoveFIrst oder.MoveLast
arbeitet und den Wert von i dann neu berechnen muß ?
Zudem besteht noch ein weiteres Problem.
angenommen n hat den Wert 10 erhalten
nun folgen die Zeilen
rs.AddNew
rs![Feldname] = <Wert>
rs.Update
rs.MoveLast
n = rs.RecordCount 'n = 11
Die Schleife würde trotzdem nur 10 mal durchlaufen
Nachzuvollziehen durch folgendes Programm
Dim n As Integer, i As Integer
n = 10
For i = 1 To n
If i = 9 Then n = 12
Next i
Debug.Print i
i = 11 und nicht 13
Gruß
Uli
>
> Gruß aus Mainz
> Michael
Michael Zimmermann wrote:
> Wenn man die datensatzweise Abarbeitung eines Recordsets
> merkbar beschleunigen will, sollte man auf das
> Do-Loop-Konstrukt völlig verzichten und stattdessen
>
> rs.MoveLast
> n = rs.RecordCount
> rs.MoveFirst
> For i = 1 To n
> rs.MoveNext
> Next i
>
> benutzen. Trotz des i. d. R. erforderlichen MoveLast schlägt
> der Geschwindigkeitsvorteil von For-Next gegen Do-Loop
> immer noch durch. Je nach Recordsetgröße in der
> Größenordnung 10% - 20%.
10-20%??? Getestet inkl .MoveLast? Du musst scherzen!!? Was meinst du mit
For-Next - kein while/do?
Bis dann,
Olaf
--
My .02: www.Resources.IntuiDev.com
Peter Doering schrieb:
> Hab ein paar Korinthen gefunden ;-)
Gewürze gehören in die Suppe :)
>>- das DROP TABLE ersetzen durch DELETE FROM TABLE
> Der ungeuebte Leser koennte die Schreibweise misverstehen. Besser so:
> DROP TABLE <Tabellenname> ... DELETE FROM <Tabellenname>
Stimmt, beim schreiben hat es mich auch gestört, bin aber nicht darauf
gekommen, was mich da störte.
>>- falls Datumsbezüge mittels Now(), Date() oder Time() in SQLs erfolgen,
>>diese auslagern
> Wie meinst du das?
Wenn du mehrere SQL Statments hast die z.B. mit WHERE [Datum]>Now()
filtern, dann kann es einfach sein, das du damit verschieden Ergebnisse
bekommst, weil es zu WHERE [Datum]>#2005-10-30 18:59:59# ein Sekunde
später zu WHERE [Datum]>#2005-10-30 19:00:00# wird.
mfG
--> stefan <--
Michel Fouquet schrieb:
> stefan hoffmann schrieb:
>> - das DROP TABLE ersetzen durch DELETE FROM TABLE
> Sollte die Verwendung des DELETE FROM-Statements aber aus genau diesen
> Gründen (Verlangsamung der Programmausführung) von Dir vorgeschlagen
> worden sein?
Nein. Durch das Löschen der Datensätze anstatt der Tabelle bleibt
TableDefs invariant. Ja mehr Invarianten beim Testen, desto besser.
mfG
--> stefan <--
Ulrich Haarmeyer:
> "Michael Zimmermann" <Zimme...@SZWeb.de>
> > Wenn man die datensatzweise Abarbeitung eines Recordsets
> > merkbar beschleunigen will, sollte man auf das
> > Do-Loop-Konstrukt völlig verzichten und stattdessen
> >
> > rs.MoveLast
> > n = rs.RecordCount
> > rs.MoveFirst
> > For i = 1 To n
> > rs.MoveNext
> > Next i
> >
> > benutzen. Trotz des i. d. R. erforderlichen MoveLast
> > schlägt der Geschwindigkeitsvorteil von For-Next gegen
> > Do-Loop immer noch durch. Je nach Recordsetgröße in der
> > Größenordnung 10% - 20%.
>
> Sicherlich, wenn man das Recordset DS für DS durchläuft.
Davon gehe ich im Normalfall aus.
| Wenn man die datensatzweise Abarbeitung eines
| Recordsets...
> Trifft das auch noch zu, wenn man mit .MovePrivious
> .MoveFIrst oder.MoveLast arbeitet und den Wert von i dann
> neu berechnen muß ?
Meistens wahrscheinlich schon. MoveFirst ist nahezu
zeitverlustfrei, spielt also für die Laufzeit keine Rolle.
Eine Manipulation einer Long-Variablen à la i = i - 1
geht ebenfalls sehr schnell vonstatten.
Im Einzelfall muß man es ausprobieren.
> Zudem besteht noch ein weiteres Problem.
> angenommen n hat den Wert 10 erhalten
> nun folgen die Zeilen
> rs.AddNew
> rs![Feldname] = <Wert>
> rs.Update
> rs.MoveLast
> n = rs.RecordCount 'n = 11
>
> Die Schleife würde trotzdem nur 10 mal durchlaufen
Wenn das /vor/ der Schleife passiert, ist das kein Problem.
Wenn das so /in/ der Schleife passiert, ist das allenfalls
ein Problem der Code-Organisation durch den Programmierer.
Nicht alles, was rein syntaktisch möglich ist, ist deswegen
auch sinnvoll.
Wenn einer erst die Datensätze zählt, dann eine Schleife
beginnt und danach in der Schleife die Datensatzanzahl
ändert, ist Datenbankentwickler der falsche Beruf für
ihn. ;-)
> Nachzuvollziehen durch folgendes Programm
> Dim n As Integer, i As Integer
> n = 10
> For i = 1 To n
> If i = 9 Then n = 12
> Next i
> Debug.Print i
>
> i = 11 und nicht 13
Das ist völlig klar, da VB(A) die For-Zeile nach
Schleifeneintritt nicht noch einmal anspringt.
Das ist einesteils bedauerlich (und es gibt auch
Uralt-Basic-Dialekte, wo das durchaus geht), anderenteils
wäre es ein ziemlich katastrophaler Programmierstil, so
daß die Trauer sich in Grenzen hält.
Da ich auf dem Standpunkt stehe, daß Datenmanipulationen
üblicherweise durch entsprechende SQL-Statements vorgenommen
werden, bleibt für das Recordset als Einsatzgebiet sowieso
nur das datensatzweise Lesen übrig.
Um das noch etwas zu verallgemeinern (ohne Recordset):
Statt
Do Until Bedingung
Machwas
Loop
kann es sogar durchaus sinnvoll sein, zunächst eine sicher
zu große Zählerobergrenze abzuschätzen, und dann
n = vielzuviel
For i = 1 To n
If Bedingung Then Exit For
Machwas
Next i
Die Betonung liegt auf 'kann'. Man muß es immer im
Einzelfall testen. Unverzichtbar ist Do Loop nur, wenn
das Eintreten der Abbruchbedingung nicht vom Durclaufen
der Schleife selbst abhängt.
> Dim n As Integer, i As Integer
Dazu noch eine Randbemerkung: Wenn Du nicht für 386er
Prozessoren programmierst, hast Du durch Integer statt
Long keinen Vorteil. Der Prozessor rechnet deine Variablen
eh auf Long hoch.
Gruß aus Mainz
Michael
Michael Zimmermann wrote:
> Hallo!
>
...
> Wenn man die datensatzweise Abarbeitung eines Recordsets
> merkbar beschleunigen will, sollte man auf das
> Do-Loop-Konstrukt völlig verzichten und stattdessen
>
> rs.MoveLast
> n = rs.RecordCount
> rs.MoveFirst
> For i = 1 To n
> rs.MoveNext
> Next i
>
> benutzen. Trotz des i. d. R. erforderlichen MoveLast schlägt
> der Geschwindigkeitsvorteil von For-Next gegen Do-Loop
> immer noch durch. Je nach Recordsetgröße in der
> Größenordnung 10% - 20%.
>
> Gruß aus Mainz
> Michael
Das kann ich nicht nachvollziehen bzw. komme zu einem gegenteiligen
Ergebnis. Liegt wahrscheinlich daran, daß ich in der For-Next-Variante
ein anderen Recordset-Typ verwenden muß. Mein Beispiel hatte 1 Mio
Datensätze aus einem Counter und einem Integerfeld:
Sub ForNext()
Dim rst As Recordset, n As Long, i As Long, sum As Long, start As
Single
start = Timer
Set rst = CurrentDb.OpenRecordset("select wert from tabelle3",
dbOpenSnapshot)
With rst
.MoveLast
n = .RecordCount
.MoveFirst
For i = 1 To n
sum = sum + .Fields(0).Value
.MoveNext
Next i
End With
Debug.Print sum & " (" & Timer - start & "s ForNext)"
End Sub
Sub DoLoop()
Dim rst As Recordset, n As Long, i As Long, sum As Long, start As
Single
start = Timer
Set rst = CurrentDb.OpenRecordset("select wert from tabelle3",
dbOpenForwardOnly)
With rst
While Not (.EOF)
sum = sum + .Fields(0).Value
.MoveNext
Wend
End With
Debug.Print sum & " (" & Timer - start & "s While)"
End Sub
Gruß
Daniel
Olaf Rabbachin:
> Michael Zimmermann wrote:
>
> > Wenn man die datensatzweise Abarbeitung eines Recordsets
> > merkbar beschleunigen will, sollte man auf das
> > Do-Loop-Konstrukt völlig verzichten und stattdessen
> >
> > rs.MoveLast
> > n = rs.RecordCount
> > rs.MoveFirst
> > For i = 1 To n
> > rs.MoveNext
> > Next i
> >
> > benutzen. Trotz des i. d. R. erforderlichen MoveLast
> > schlägt der Geschwindigkeitsvorteil von For-Next gegen
> > Do-Loop immer noch durch. Je nach Recordsetgröße in der
> > Größenordnung 10% - 20%.
>
> 10-20%??? Getestet inkl .MoveLast?
Ja, klar inklusive MoveLast. Da das erforderlich ist, wäre
es ohne ja gemogelt.
> Du musst scherzen!!?
Du kennst mich doch. Komme ich hierher und erzähle Witze?
Wär ja das erste Mal. ;-)
Oder bist Du so ungläubig, weil ich nach den Tricks mit
bis zu 17000% Steigerung im Vortrag bei der AEK jetzt mit
popeligen 20% ankomme?
> Was meinst du mit For-Next - kein while/do?
Der Code steht doch da oben. Aber, damit's ganz klar ist:
'\\\Schneller
rs.MoveLast
n = rs.RecordCount
rs.MoveFirst
For i = 1 To n
rs.MoveNext
Next i
'///
'\\\Langsamer
Do Until rs.EOF
rs.MoveNext
Loop
'///
Gruß aus Mainz
Michael
> Das kann ich nicht nachvollziehen bzw. komme zu einem gegenteiligen
> Ergebnis. Liegt wahrscheinlich daran, daß ich in der For-Next-Variante
> ein anderen Recordset-Typ verwenden muß.
Richtig!
Dein Snapshot ist wahrscheinlich 95% der Zeit damit
beschäftigt, zuerst die Tabelle in den RAM zu laden.
Aber warum *muß*?
For i = 1 To MAX_WB_LONG
If rs.EOF Then exit For
sum = sum + .Fields(0).Value
.MoveNext
Next i
;-)
Gruß
Daniel Liebig:
> Michael Zimmermann wrote:
> ...
> > Wenn man die datensatzweise Abarbeitung eines Recordsets
> > merkbar beschleunigen will, sollte man auf das
> > Do-Loop-Konstrukt völlig verzichten und stattdessen
> >
> > rs.MoveLast
> > n = rs.RecordCount
> > rs.MoveFirst
> > For i = 1 To n
> > rs.MoveNext
> > Next i
> >
> > benutzen. Trotz des i. d. R. erforderlichen MoveLast
> > schlägt der Geschwindigkeitsvorteil von For-Next gegen
> > Do-Loop immer noch durch. Je nach Recordsetgröße in der
> > Größenordnung 10% - 20%.
> Das kann ich nicht nachvollziehen bzw. komme zu einem
> gegenteiligen Ergebnis. Liegt wahrscheinlich daran, daß
> ich in der For-Next-Variante ein anderen Recordset-Typ
> verwenden muß.
... verwendet /hast/.
Ich bin bei beiden Beispielen, wie man am Code ja sieht, von
einem Dynaset ausgegangen.
Dann verhält es sich so, wie ich geschrieben habe.
Gruß aus Mainz
Michael
"Michael Zimmermann" <Zimme...@SZWeb.de> schrieb im Newsbeitrag
news:43651904$0$21941$9b4e...@newsread2.arcor-online.net...
Nur um den Fehler: "Kein aktueller Datensatz" zu vermeiden:
n = rs.RecordCount-1
oder
For i = 1 To n-1
> '\\\Langsamer
> Do Until rs.EOF
> rs.MoveNext
> Loop
> '///
Gruß aus Dortmund
Uli
Joerg Ackermann:
> Aber warum *muß*?
>
> For i = 1 To MAX_WB_LONG
> If rs.EOF Then exit For
> sum = sum + .Fields(0).Value
> .MoveNext
> Next i
Ob das /so/ noch einen Vorteil bringt, würde ich nicht
unterschreiben, ohne es vorher getestet zu haben.
Einer der großen Vorteile von For-Next, daß nicht bei jedem
Schleifendurchlauf eine Abbruchbedingung geprüft werden muß,
geht so verloren.
Im Einzelfall kann es aber durchaus sein.
Gruß aus Mainz
Michael
Joerg Ackermann wrote:
ok, auch das Dynaset ist schneller, kann die Variante ForwardOnly aber
trotzdem nicht erreichen, hat zumindest mein Test ergeben. Also bringt
mir das .MoveLast nie einen Vorteil. Und ob While oder For - der
Unterschied dürfte wohl nicht vorhanden sein.
Gruß
Daniel
Michael Zimmermann wrote:
> Hallo!
>
...
>
> ... verwendet /hast/.
>
> Ich bin bei beiden Beispielen, wie man am Code ja sieht, von
> einem Dynaset ausgegangen.
>
> Dann verhält es sich so, wie ich geschrieben habe.
>
> Gruß aus Mainz
> Michael
wenn es aber darum geht, die schnellste Variante zu finden, nehme ich
auch den schnellsten Recordset-Typ. Und ForwardOnly ist nunmal bei
MoveLast und zurück nicht möglich. Snapshot nimmst du in deinem Beispiel
ja schließlich auch nicht ;-)
Gruß
Daniel
Ulrich Haarmeyer:
> > '\\\Schneller
> > rs.MoveLast
> > n = rs.RecordCount
> > rs.MoveFirst
> > For i = 1 To n
> > rs.MoveNext
> > Next i
> > '///
>
> Nur um den Fehler: "Kein aktueller Datensatz" zu
> vermeiden: n = rs.RecordCount-1
> oder
> For i = 1 To n-1
Nein, mein Code paßt schon, probier's aus. Dabei setze ich
natürlich voraus, daß rs.Movenext, wie es logisch ist, die
letzte Anweisung im Schleifenblock ist:
For i = 1 To n
rs.Machwas
rs.Machnochwas
rs.MoveNext
Next i
Gruß aus Mainz
Michael
Daniel Liebig:
> Und ob While oder For - der Unterschied
> dürfte wohl nicht vorhanden sein.
Das ist der /Haupt/unterschied.
For i = 1 To n
Next i
0,8
For i = 1 To n
x = x + 1
Next i
2,8
Do While i < n
i = i + 1
Loop
4,9
Alle Variablen Long
Gruß aus Mainz
Michael
"Michael Zimmermann" <Zimme...@SZWeb.de> schrieb im Newsbeitrag
news:43651fbf$0$21945$9b4e...@newsread2.arcor-online.net...
Stimmt, sorry, ziehe jegliche Behauptung zurück.
Hatte beim Testen das .rs.MoveFirst nach dem .RecordCount vergessen *Schäm
Gruß
Uli
Daniel Liebig:
> wenn es aber darum geht, die schnellste Variante zu
> finden, nehme ich auch den schnellsten Recordset-Typ. Und
> ForwardOnly ...
So kocht es die Gerüchteküche.
Die QueryPerformaceCounter-API aber sagt:
ForwardOnly
0, 213 950 s
0, 286 477 s
0, 252 866 s
0, 291 450 s
DynaSet
0, 197 561 s
0, 276 489 s
0, 204 232 s
0, 245 362 s
Also, ich finde Dynaset gar nicht soo übel. ;-)
Gruß aus Mainz
Michael
Michael Zimmermann wrote:
stimmt, der Unterschied zwischen For und Do ist tatsächlich immens -
trotzdem bleibt do im Beispiel schneller, probiers halt aus.
Gruß Daniel
Sub ForNext()
Dim rst As Recordset, n As Long, i As Long, sum As Long, start As
Single
start = Timer
Set rst = CurrentDb.OpenRecordset("select wert from tabelle3",
dbOpenDynaset)
With rst
.MoveLast
n = .RecordCount
.MoveFirst
For i = 1 To n
sum = sum + .Fields(0).Value
.MoveNext
Next i
End With
Debug.Print sum & " (" & Timer - start & "s ForNext)"
End Sub
Sub LoopDo()
Dim rst As Recordset, i As Long, sum As Long, start As Single
start = Timer
Set rst = CurrentDb.OpenRecordset("select wert from tabelle3",
dbOpenForwardOnly)
With rst
While Not (.EOF)
sum = sum + .Fields(0).Value
.MoveNext
Wend
End With
Debug.Print sum & " (" & Timer - start & "s While)"
End Sub
2097152 (7,117188s ForNext)
2097152 (7,03125s ForNext)
2097152 (6,976563s ForNext)
2097152 (6,617188s While)
2097152 (6,625s While)
2097152 (6,632813s While)
2097152 (6,632813s While)
2097152 (7,007813s ForNext)
2097152 (7,015625s ForNext)
2097152 (6,6875s While)
2097152 (6,609375s While)
2097152 (7,015625s ForNext)
2097152 (7s ForNext)
"Michael Zimmermann" <Zimme...@SZWeb.de> schrieb im Newsbeitrag
news:436522df$0$21956$9b4e...@newsread2.arcor-online.net...
Das ForNext schneller ist als While not EOF lässt sich bei mir nicht
nachvollziehen.
Testtabelle mit einem Feld, Typ LongInteger mit 10000 Datensätzen
Feldinhalte 1 bis 10000
Allerdings habe ich beim Test DAO.Recordsets verwendet.
Folgende Subs:
Sub ForNext()
Dim db As DAO.Database, rst As DAO.Recordset, n As Long, _
i As Long, sum As Long, start As Single
Set db = CurrentDb
start = Timer
Set rst = db.OpenRecordset("select Feldx from tabelle4")
With rst
.MoveLast
n = .RecordCount
.MoveFirst
For i = 1 To n
sum = sum + .Fields(0).Value
.MoveNext
Next i
End With
Debug.Print sum & " (" & Timer - start & " s ForNext)"
rst.Close
End Sub
Sub DoLoop()
Dim db As DAO.Database, rst As DAO.Recordset, n As Long, _
i As Long, sum As Long, start As Single
Set db = CurrentDb
start = Timer
Set rst = db.OpenRecordset("select Feldx from tabelle4")
With rst
While Not (.EOF)
sum = sum + .Fields(0).Value
.MoveNext
Wend
End With
Debug.Print sum & " (" & Timer - start & " s While)"
rst.Close
End Sub
Ergebnis im Direktfenster:
50005000 (0,03125 s ForNext)
50005000 (0,03125 s While)
Die Subs wurden unmittelbar nacheinander durch Anklicken einer
Befehlsschaltfläche ausgeführt.
Mehrfache Durchläufe brachten kein abweichendes Ergebnis. Die Werte warten
immer identisch.
Gruß
Uli
Michael Zimmermann schrieb:
> Daniel Liebig:
>> wenn es aber darum geht, die schnellste Variante zu
>> finden, nehme ich auch den schnellsten Recordset-Typ. Und
>> ForwardOnly ...
>
> So kocht es die Gerüchteküche.
Ich will auch mitkochen. ;-)
> Die QueryPerformaceCounter-API aber sagt:
>
> ForwardOnly
> 0, 213 950 s
> 0, 286 477 s
> 0, 252 866 s
> 0, 291 450 s
>
> DynaSet
> 0, 197 561 s
> 0, 276 489 s
> 0, 204 232 s
> 0, 245 362 s
>
> Also, ich finde Dynaset gar nicht soo übel. ;-)
Bei mir sagt die QueryPerformaceCounter-API:
ForwardOnly: 7,8s
DynaSet: 9,3s
setze ich noch zusätzlich
dim fld as dao.field
set fld = rst.fields(0)
<schleife>
... = fdl
</schleife>
ergibt das eine Zeit von:
ForwardOnly: 5,5s
DynaSet: 8,5s
Man kann auch die DynaSet-Variante noch etwas beschleunigen:
a = rst.GetRows(rst.RecordCount)
und anschließend nur noch das Array-Feld durchlaufen
ForwardOnly: --- (funktioniert nicht)
DynaSet: 6,5s
In diesem Beispiel (2.6 Mio DS) hat ForwardOnly "gewonnen".
Andererseits muss ich gestehen, dass ich sehr selten im Code ein
Recordset mit mehreren DS zum Auswerten durchlaufe.
Meist werte ich nur einen einzelnen DS per VBA aus. - Und in so einem
Fall kann sogar Snapshot schneller sein.
Nicht vergessen werden darf auf dbOpenTable.
OpenTable (fld-Syntax): 4,2s
mfg
Josef
--
EPT: (Access Error Prevention Table) http://access.joposol.com/
FAQ: (Access-FAQ von Karl Donaubauer) http://www.donkarl.com/
Josef Poetzl:
> Michael Zimmermann schrieb:
> > Daniel Liebig:
> > > wenn es aber darum geht, die schnellste Variante zu
> > > finden, nehme ich auch den schnellsten Recordset-Typ.
> > > Und ForwardOnly ...
> >
> > So kocht es die Gerüchteküche.
>
> Ich will auch mitkochen. ;-)
>
> > Die QueryPerformaceCounter-API aber sagt:
> >
> > ForwardOnly
> > 0, 213 950 s
> > 0, 286 477 s
> > 0, 252 866 s
> > 0, 291 450 s
> >
> > DynaSet
> > 0, 197 561 s
> > 0, 276 489 s
> > 0, 204 232 s
> > 0, 245 362 s
> >
> > Also, ich finde Dynaset gar nicht soo übel. ;-)
>
> Bei mir sagt die QueryPerformaceCounter-API:
> ForwardOnly: 7,8s
> DynaSet: 9,3s
Verrate mir den Trick. Ich will ja auch wieder glauben,
daß Forward schneller als dynamisch ist, aber mein Rechner
weigert sich. ;-)
> setze ich noch zusätzlich
> dim fld as dao.field
^^^
> set fld = rst.fields(0)
> <schleife>
> ... = fdl
^^^
> </schleife>
>
> ergibt das eine Zeit von:
> ForwardOnly: 5,5s
> DynaSet: 8,5s
Kann ich nicht bestätigen. Gibt bei mir die Fehlermeldung
"Variable nicht deklariert". ;-)
> ...
> Nicht vergessen werden darf auf dbOpenTable.
> OpenTable (fld-Syntax): 4,2s
In der Praxis meistens nutzlos: Es gibt doch keine lokalen
Tabellen. Jednfalls keine, die ausreichend Daten enthalten,
daß man sich über Performance Gedanken machen muß.
Gruß aus Mainz
Michael
Ulrich Haarmeyer:
> Die Subs wurden unmittelbar nacheinander durch Anklicken
> einer Befehlsschaltfläche ausgeführt.
> Mehrfache Durchläufe brachten kein abweichendes Ergebnis.
> Die Werte warten immer identisch.
Das liegt an der viel zu ungenauen Timer-Funktion, bzw.
an zu kleinen Recordsets.
Siehe auch mein anderes Posting. Messen ist nichts, was man
einfach aus dem Ärmel schüttelt. Du kannst jeden Physiker
- mich z. B. ;-) - fragen, daß dazu genaue Überlegungen
zur Größenordnung der zu erwartenden Messungen, Auflösung
des Meßinstruments, Errechnung von methodischen und
statistischen Fehlern, Größenisolierung etc. pp. gehören.
Nimm folgende Analogie: Du hast mit einem Chronometer, das
anzeigt: 1 Woche, 2 Wochen, 3 Wochen, festgestellt, daß
Doktor Schiwago und die Tagesschau genau gleichlang
dauern, nämlich eine Woche. ;-)
Gruß aus Mainz
Michael
Daniel Liebig:
> > > Und ob While oder For - der Unterschied
> > > dürfte wohl nicht vorhanden sein.
> >
> >
> > Das ist der /Haupt/unterschied.
> >
> > For i = 1 To n
> >
> > Next i
> > 0,8
> >
> > For i = 1 To n
> > x = x + 1
> > Next i
> > 2,8
> >
> > Do While i < n
> > i = i + 1
> > Loop
> > 4,9
> >
> > Alle Variablen Long
> >
> > Gruß aus Mainz
> > Michael
>
> stimmt, der Unterschied zwischen For und Do ist
> tatsächlich immens - trotzdem bleibt do im Beispiel
> schneller, probiers halt aus.
Was glaubst Du, wie oft ich das schon getan habe. ;-)
> 2097152 (7,117188s ForNext)
> 2097152 (7,03125s ForNext)
> 2097152 (6,976563s ForNext)
> 2097152 (6,617188s While)
> 2097152 (6,625s While)
> 2097152 (6,632813s While)
> 2097152 (6,632813s While)
> 2097152 (7,007813s ForNext)
> 2097152 (7,015625s ForNext)
> 2097152 (6,6875s While)
> 2097152 (6,609375s While)
> 2097152 (7,015625s ForNext)
> 2097152 (7s ForNext)
ForNext
0, 467 207 s
0, 425 830 s
0, 388 490 s
0, 444 217 s
0, 371 551 s
DoLoop
0, 630 480 s
0, 404 741 s
0, 510 386 s
0, 433 703 s
0, 423 579 s
Noch ein paar Worte zur Meßmethodik:
Zunächst mal sind Messungen mit Timer oder Now() entschieden
zu grob, um damit viel Sinnvolles anfangen zu können.
Auch die Konkurrenten
Declare Function GetTickCount Lib "kernel32" () As Long
Declare Function timeGetTime Lib "winmm.dll" () As Long
sind zu unscharf.
Es gibt für genaue Messungen die hochauflösenden Funktion
Private Declare Function QueryPerformanceCounter _
Lib "kernel32" ( _
x As Currency) _
As Boolean
Private Declare Function QueryPerformanceFrequency _
Lib "kernel32" ( _
x As Currency) _
As Boolean
Du findest dazu auch einen KB-Artikel, der den Einsatz
beschreibt. Nicht ernstnehmen darf man diesen allerdings,
wo er dynamisch den Abzug des Overheads vornimmt. Die
dazu beschriebene Vorgehensweise ist blühender Unfug.
So gesehen ist der Artikel nur bedingt empfehlenswert, zeigt
aber immerhin das prinzipielle Procedere.
Zum zweiten muß man, um die Auswirkungen eines Parameters
richtig beurteilen zu können, alle anderen konstant halten.
Wenn man in der Schleife, egal ob For-Next oder Do-Loop
genügend viele und zeitaufwendige Aktionen unterbringt,
gehen sogar die erheblichen Unterschiede zugunsten
der nackten For-Next-Schleife irgendwann völlig unter.
Um das Zeitverhalten der Schleifen an sich beurteilen zu
können, solltest Du nur diese messen - also die
RS-Erstellung, die ja bei beiden gleich ist, nicht
mitmessen und den Schleifeninhalt auf MoveNext reduzieren.
Wie Du es geschafft hast, daß die Do-Loop-Schleife über
ein Recordset - wenn auch nur minimal - schneller sein soll
als For-Next, ist mir allerdings ein Rätsel - ich habe
seit Jahren Hunderte von solchen Dingern gemessen nebst
Fehlerrechnung mit Standardabweichungen und allem Pipapo -
auch beim Test gerade eben hat For die Nase vorn.
Tut mir leid, ich kann's nicht ändern.
Hat Deine "Tabelle3" (das klingt so nach zum Testen
zusammengebastelt) vielleicht keinen Primärschlüssel
oder eindeutigen Index? Das würde das MoveLast ausbremsen.
Das ist rein logisch, wenn ansonsten genau das gleiche
passiert, die einzige Möglichkeit, wie ein Do-Loop das
schnellere For-Next überholen könnte: daß das MoveLast
den Zeitgewinn wieder auffrißt. Mir ist aber so ein Fall
unter Feldbedingungen noch nie untergekommen.
Es gibt weitere Seiteneffekte:
Wenn Du zwei Vorgehensweisen vergleichst, die mit
gleichartigen Variablentypen arbeiten, oder dieselbe
Prozedur mehrmals kurz hintereinander ausführst, hat
der Code, der später ausgeführt wird, oft eine höhere
Geschwindigkeit. Ich vermute, daß das mit
Speicheroptimierungsstrategien von Access einerseits
und dem Betriebssytem andererseits zu tun hat.
Zwischen zwei Testdurchläufen solltest Du also mehrere
Sekunden warten und auch die Reihenfolge, in der die
Prozeduren ausgeführt werden, ab und an vertauschen.
Gruß aus Mainz
Michael
Michael Zimmermann wrote:
> Hallo!
...
>
> Es gibt weitere Seiteneffekte:
>
> Wenn Du zwei Vorgehensweisen vergleichst, die mit
> gleichartigen Variablentypen arbeiten, oder dieselbe
> Prozedur mehrmals kurz hintereinander ausführst, hat
> der Code, der später ausgeführt wird, oft eine höhere
> Geschwindigkeit. Ich vermute, daß das mit
> Speicheroptimierungsstrategien von Access einerseits
> und dem Betriebssytem andererseits zu tun hat.
>
> Zwischen zwei Testdurchläufen solltest Du also mehrere
> Sekunden warten und auch die Reihenfolge, in der die
> Prozeduren ausgeführt werden, ab und an vertauschen.
>
> Gruß aus Mainz
> Michael
Hi Michael,
wie du schon geschrieben hast, ist eine Schleife mit do, die die reine
For-Next Struktur nachbaut langsamer. Aber im Problem ging es ja nicht
darum, sondern ob das .MoveLast und .MoveFirst etwas bringt. Und da
konnte ich in keiner Konstellation einen Vorteil ermitteln. Selbst die
Variante mit einem MAX_WB_LONG von Jörg, die auch ein dbOpenForwardOnly
verwenden kann, bringt keine Vorteil. Im bestehenden Fall entfällt im
Loop nämlich das iterieren einen Abbruchzählers und es fällt lediglich
die .eof-Prüfung an. Egal mit wievielen DS ich getestet habe - die
Geschwindigkeit der For-Next kann das .MoveLast und die Verwendung eines
Dynasets nicht kompensieren und darum ging es ja schließlich - um die
gesamte Funktionalität und nicht um einen Teil davon.
Mein Testszenario:
DAO, Acc97
Tabelle3 (id counter primary key, wert int) Wert immer gleich 1
wie an der Ausgabe zu sehen - mit gut 2Mio DS getestet - der Abstand
bleibt auch mit der doppelten Anzahl etwa gleich
Und kurz etwas zur Zeitmessung - klar, wenn ich im 0,...s -Bereich
messe, mag Timer() durch die geringe Auflösung ungeeignet sein, bei so
hohen Zeiten reicht es aber völlig aus um Anhaltspunkte zu erhalten. Wie
du an der wechselnden Ausgabe erkennen kannst, habe ich die
Reihenfolge der Ausführung durchaus variiert. Das ists also auch nicht -
bleibt mein Prozessor - AMD, macht der vielleicht etwas anders?
Gruß Daniel
Michael Zimmermann schrieb:
> Josef Poetzl:
>> Bei mir sagt die QueryPerformaceCounter-API:
>> ForwardOnly: 7,8s
>> DynaSet: 9,3s
>
> Verrate mir den Trick. Ich will ja auch wieder glauben,
> daß Forward schneller als dynamisch ist, aber mein Rechner
> weigert sich. ;-)
Kein Trick. - Nicht einmal Dein Trick (die Rst-Erstellung nicht
mitmessen) macht bei mir die DynaSet schneller als ForwardOnly.
so testete ich:
ForwardOnly:
StartT
Set rst = db.OpenRecordset(SQL, dbOpenForwardOnly)
Set fld = rst.Fields(0)
While Not rst.EOF ' kein Unterschied zu: Do until
lngWert = fld
rst.MoveNext
Wend
Set fld = Nothing
Set rst = Nothing
StopT
Dynaset:
StartT
Set rst = db.OpenRecordset(SQL, dbOpenDynaset)
rst.MoveLast
rst.MoveFirst
lngMaxCnt = rst.RecordCount
Set fld = rst.Fields(0)
For i = 1 To lngMaxCnt
lngWert = fld
rst.MoveNext
Next
Set fld = Nothing
Set rst = Nothing
StopT
SQL = "SELECT ID FROM Tabelle"
Tabelle = Tab auf Netzlaufwerk mit 2,6 Mio DS
db = DAO.Database des BE
Testumgebung:
WinXP SP2, AcXP SP3
>> ...
>> Nicht vergessen werden darf auf dbOpenTable.
>> OpenTable (fld-Syntax): 4,2s
>
> In der Praxis meistens nutzlos: Es gibt doch keine lokalen
> Tabellen. Jednfalls keine, die ausreichend Daten enthalten,
> daß man sich über Performance Gedanken machen muß.
Das "lokale" Argument ist ja kein Problem, das kann man umgehen.
Die geringe "Praxistauglichkeit" kommt für mich eher daher, dass ich
nie alle DS einer Tabelle per VBA auswerten will.
Daniel Liebig:
> wie du schon geschrieben hast, ist eine Schleife mit do,
> die die reine For-Next Struktur nachbaut langsamer. Aber
> im Problem ging es ja nicht darum, sondern ob das
> .MoveLast und .MoveFirst etwas bringt.
Nein, das hast Du mißverstanden.
Der Code-Block
rs.MoveLast
n = rs.RecordCount
rs.MoveFirst
bringt ganz sicher /nichts/ für die Performance, sondern
ist im Gegenteil abträglich.
Es ist aber für die Verwendung von For-Next ein /notwendiges
Übel/, da ein DAO.Recordset ohne MoveLast nicht sicher die
richtige Datensatzanzahl liefert.
RecordCount und MoveFirst sind dabei unschädlich, da sie
fast keine Zeit verbrauchen. Das MoveLast braucht allerdings
eine Weile.
> Im bestehenden Fall entfällt im Loop nämlich das
> iterieren einen Abbruchzählers und es fällt lediglich die
> .eof-Prüfung an.
Das ist aber genau der Punkt. Es muß bei jedem
Schleifendurchlauf Aufwand betrieben werden, um die
Abbruchbedingung zu prüfen. Bei der For-Schleife findet
ein interner Zähler Verwendung, der als Prozessorbefehl
das Inkrement benutzt, eine der schnellsten Operationen
überhaupt.
> Egal mit wievielen DS ich getestet habe
> - die Geschwindigkeit der For-Next kann das .MoveLast und
> die Verwendung eines Dynasets nicht kompensieren und
> darum ging es ja schließlich - um die gesamte
> Funktionalität und nicht um einen Teil davon.
Sicher, allerdings benutze ich in beiden Szenarien ein
Dynaset.
Ich habe es, wie gesagt, nicht geschafft, ein Do-Loop
dabei schneller als ein For-Next werden zu lassen.
Ich habe früher auch immer Do Until rs.EOF - Loop benutzt,
und bin erst, seit ich immer wieder For-Next als schneller
festgestellt hatte, auf dieses umgestiegen.
> ... - bleibt mein Prozessor - AMD, macht der
> vielleicht etwas anders?
Daran hängt's nicht, bei mir werkelt auch ein AMD.
Der Geschwindigkeitsunterschied Ganzzahl versus
Gleitkommazahl, der ist meßbar prozessorabhängig.
Es könnte aber an Deiner nostalgischen Access-Version
liegen. Wenn die Algoritmen, um den letzten Datensatz
aufzufinden, seitdem verbessert wurden, kann das genau
der Grund sein, warum Dein MoveLast etwas länger braucht
als meines und damit den For-Next-Vorsprung auffrißt.
Die Tests, die ich gemacht habe, basieren alle auf XP/2003.
Im Zweifel sollte man einfach beide Varianten probieren und
die im Einzelfall schnellere benutzen.
Gruß aus Mainz
Michael
Josef Poetzl:
> Michael Zimmermann schrieb:
> > Josef Poetzl:
> > > Bei mir sagt die QueryPerformaceCounter-API:
> > > ForwardOnly: 7,8s
> > > DynaSet: 9,3s
> >
> > Verrate mir den Trick. Ich will ja auch wieder glauben,
> > daß Forward schneller als dynamisch ist, aber mein
> > Rechner weigert sich. ;-)
>
> Kein Trick. - Nicht einmal Dein Trick (die Rst-Erstellung
> nicht mitmessen) macht bei mir die DynaSet schneller als
> ForwardOnly.
Vielleicht ein Standortproblem. Du hast wahrscheinlich
östereichische Ländereinstellungen. ;-)
> > > ...
> > > Nicht vergessen werden darf auf dbOpenTable.
> > > OpenTable (fld-Syntax): 4,2s
> >
> > In der Praxis meistens nutzlos: Es gibt doch keine
> > lokalen Tabellen. Jednfalls keine, die ausreichend
> > Daten enthalten, daß man sich über Performance Gedanken
> > machen muß.
>
> Das "lokale" Argument ist ja kein Problem, das kann man
> umgehen.
Willst Du auf FE/BE-Trennung verzichten, damit Du
dbOpenTable benutzen kannst? ;-)
Gruß aus Mainz
Michael
MFG
Stefan
Ich hab den Grund für die falsche Berechnung jetzt herausgefunden bin
mir aber nicht sicher ob ich jetzt einen Fehler gemacht hab oder Access.
Bei der Monatsstatistik ist die Reihenfolge der Einträge in einem
Recordset wichtig, sonst rechnet er falsch. Und wenn der Code normal
abläuft ist die Reihenfolge in diesem Recordset anders als wenn das
ganze im Debug-Modus abläuft.
Ich bin darauf gekommen als ich in der While Schleife mit debug.print
immer einen Wert des Recordsets ausgelesen hab und da war das Resultat
im Debug Modus unterschiedlich.
Folgende Zeile ist betroffen:
----
Set R1 = dbs.OpenRecordset("SELECT * FROM tbl_MD ORDER BY PersonalID,
Anspruchsbeginn", dbOpenDynaset)
----
Obwohl ich da extra ne ORDER BY Klausel drin hab ist die Reihenfolge im
Recordset unterschiedlich.
Die Daten die importiert werden sind schon in der richtigen Reihenfolge,
da aber alles mit INSERT Anweisungen in die Tabelle geschrieben wird
kann man nicht sagen das in der Tabelle dann auch die gleiche
Reihenfolge, intern, verwendet wird, deshalb hab ich beim öffnen des
Recordsets einfach ne ORDER BY Klausel hinzugefügt. Ist daran was falsch
oder gibt es ne bessere Lösung?
MFG
Stefan
Michael Zimmermann schrieb:
> Private Declare Function QueryPerformanceFrequency _
> Lib "kernel32" ( _
> x As Currency) _
> As Boolean
Hmm, gibts eigentlich ein Office für Alphas? Der Datentyp ist eigentlich
LARGE_INTEGER.
Bei mir kommt mal gerade ~3,5Mhz raus. Kann das sein?
mfG
--> stefan <--
stefan hoffmann:
> Michael Zimmermann schrieb:
> > Private Declare Function QueryPerformanceFrequency _
> > Lib "kernel32" ( _
> > x As Currency) _
> > As Boolean
> Hmm, gibts eigentlich ein Office für Alphas? Der Datentyp
> ist eigentlich LARGE_INTEGER.
64 Bit halt.
> Bei mir kommt mal gerade ~3,5Mhz raus. Kann das sein?
Faktor 10000 wegen Currency-Skalierung hast Du bedacht?
Wenn ja: Hast Du einen 386 SX oder schon DX? ;-)
Gruß aus Mainz
Michael
Michael Zimmermann schrieb:
>> Bei mir kommt mal gerade ~3,5Mhz raus. Kann das sein?
> Faktor 10000 wegen Currency-Skalierung hast Du bedacht?
357,9545 * 10000 = 3579545 ~ 3,5MHz
> Wenn ja: Hast Du einen 386 SX oder schon DX? ;-)
Wohl eher SX, da ich das mit der Umrechnung gerade auf keinem Aug' blick.
mfG
--> stefan <--
stefan hoffmann:
Das ist wohl kaum der Prozessortakt, sondern eher ein
woraus auch immer von Windows generierter "Systemtakt".
Falls es Dich genauer interessiert, ist die Frage, wie
Windows seine Counter-Schritte baut, wahrscheinlich in
der VB-Gruppe gut aufgehoben.
Gruß aus Mainz
Michael
stefan hoffmann wrote:
> Peter Doering schrieb:
>
>>>- falls Datumsbezüge mittels Now(), Date() oder Time() in SQLs erfolgen,
>>>diese auslagern
>> Wie meinst du das?
> Wenn du mehrere SQL Statments hast die z.B. mit WHERE [Datum]>Now()
> filtern, dann kann es einfach sein, das du damit verschieden Ergebnisse
> bekommst, weil es zu WHERE [Datum]>#2005-10-30 18:59:59# ein Sekunde
> später zu WHERE [Datum]>#2005-10-30 19:00:00# wird.
Ach das hast du gemeint. Das kann man auch so umschiffen, indem man beim
String-Aufbau aufpasst:
strSQL = "SELECT ... FROM ... WHERE [Datum]> " & _
Format(Now(),"\#yyyy\-mm\-dd\#" & ";"
;-)
Gruss - Peter
--
Ich beantworte keine Fragen per Email.
Mitglied im http://www.dbdev.org
FAQ: http://www.donkarl.com
Michael Zimmermann schrieb:
>> Michael Zimmermann schrieb:
>> > > Bei mir kommt mal gerade ~3,5Mhz raus. Kann das sein?
>> > Faktor 10000 wegen Currency-Skalierung hast Du bedacht?
>> 357,9545 * 10000 = 3579545 ~ 3,5MHz
> Das ist wohl kaum der Prozessortakt, sondern eher ein
> woraus auch immer von Windows generierter "Systemtakt".
Na.
QueryPerformanceFrequency liefert in der LARGE_INTEGER Struktur als Wert
3579545. Laut SDK sind das Zählschritte pro Sekunde. In der
Currency-Variante kommt 357,9545 als Wert heraus.
Das Auflösungsvermögen von QueryPerformanceCounter sollte somit ~3,5 MHz
(=1/s) betragen.
mfG
--> stefan <--
Stefan Schmidhammer wrote:
> Folgende Zeile ist betroffen:
> ----
> Set R1 = dbs.OpenRecordset("SELECT * FROM tbl_MD ORDER BY PersonalID,
> Anspruchsbeginn", dbOpenDynaset)
> ----
>
> Obwohl ich da extra ne ORDER BY Klausel drin hab ist die Reihenfolge im
> Recordset unterschiedlich.
was für einen Typ hat [Anspruchsbeginn]? Falls numerische Werte darin
gespeichert werden sollen, der Feldtyp jedoch auf Text steht, wirst du
nicht die gewünschte Sortierung erhalten.
Bis dann,
Olaf
--
My .02: www.Resources.IntuiDev.com
Stefan Schmidhammer schrieb:
> Bei der Monatsstatistik ist die Reihenfolge der Einträge in einem
> Recordset wichtig, sonst rechnet er falsch.
also mich wundert ja, dass diese Aussage noch nicht den MZausMZ auf den
Plan gerufen hat. Darf denn die Reihenfolge der DS eine so entscheidende
Rolle bei einer Berechnung spielen?
Wie dem auch sei, ein Blick in die OH VB bringt Dich ggf. weiter.
> Folgende Zeile ist betroffen:
> ----
> Set R1 = dbs.OpenRecordset("SELECT * FROM tbl_MD ORDER BY PersonalID,
> Anspruchsbeginn", dbOpenDynaset)
> ----
>
> Obwohl ich da extra ne ORDER BY Klausel drin hab ist die Reihenfolge im
> Recordset unterschiedlich.
Schau Dir doch mal zum Recordset die Eigenschaften "Sort" und "Index"
an! *Damit* regelst Du IMHO die Reihenfolge.
mfg,
Michel
Michel Fouquet:
> > Bei der Monatsstatistik ist die Reihenfolge der
> > Einträge in einem Recordset wichtig, sonst rechnet er
> > falsch.
>
> also mich wundert ja, dass diese Aussage noch nicht
> den MZausMZ auf den Plan gerufen hat. Darf denn die
> Reihenfolge der DS eine so entscheidende Rolle bei
> einer Berechnung spielen?
Natürlich.
Das kann zum einen an der logischen Struktur liegen, z. B.
bei einer laufenden Summe nach Monaten oder bei Addition
von Blättern eines B-Baumes nach hierarchisch geordneten
Kategorieebenen.
Wenn diese logische Reihenfolge nur in der physischen
Reihenfolge der DS zum Ausdruck kommt, wäre das natürlich
katastrophal, d. h. ein Feld mit Daten, die diese
Reihenfolge eindeutig festlegen, ist natürlich Pflicht.
Zum anderen gibt es die gar nicht mal so seltene
Möglichkeit, daß eine Berechnung zwar auch ohne bestimmte
Reihenfolge durchführbar wäre, bei geordnetem Vorliegen
aber ein Algorithmus mit weitaus besserem Zeitverhalten
angewandt werden kann.
Beispiel: Minimum-Suche in 1000 ungeordneten Zahlen erfodert
im zeitlichen Mittel 500 Schritte, in geordneten Zahlen
konstant nur einen Schritt.
Gruß aus Mainz
Michael
Michael Zimmermann schrieb:
>> Darf denn die
>> Reihenfolge der DS eine so entscheidende Rolle bei
>> einer Berechnung spielen?
>
> Natürlich.
[Erklärung gesnippt]
Danke. Da muss ich mich beim Schreiben wohl in einem Zustand der
mittelschweren geistigen Umnachtung befunden haben.
Bei der Lektüre Deines Postings sich heftigst an die Stirn klatschend,
Michel