Statt TADOTable TADOQuery nehmen. Scheint sich (zuweilen) etwas dynamischer zu verhalten.
Aha, interessant. Also die ADOTable einfach durch eine ADOQuery mit Abfrage "Select * from..." ersetzen, das ist dann gleichwertig? Die
Query kann auch .Edit und .Append?
Ja, bei einem Select * from tabelle where irgendeinebedingung geht das problemlos. Bei Joins über mehrere Tabellen geht's nicht. Da TAdoQuery nur eine Tabelle kann, kannst Du das durch eine TADOQuery (mit 'nem entsprechenden Select) ersetzen.
Benötigst Du tatsächlich alle Daten der Tabelle immer an "einem Stück"?
Denke schon, da in einem Zuge auf a) Vorhandensein und b) Gleichheit der jeweiligen Quelltabellen-Zeile in der Zieltabelle geprüft und dann ggfs. die Zeile entweder eingefügt oder aktualisiert wird. Dazu muss der Vergleich ja immer die Zieltabelle als Ganzes sehen, oder?
Das kann man aber auch anders lösen. Tabelle A in sinnvollen Teilmengen laden (
Query mit passender Wherebedingung) und satzweise durchgehen. Genau diesen einen Satz per weiterer
Query in der Tabelle B suchen. Prüfen, einfügen und aktuallisieren dieses Satzes wie bisher.
Was genau wird gemacht? Tabelle lesen und woanders schreiben?
Mehrere Tabellen aus einer Quell-Datenbank werden mit den entsprechenden Tabellen in einer Ziel-Datenbank abgeglichen. Wenn die Quellzeile in der Zieltabelle nicht vorhanden ist, wird sie eingefügt, ansonsten aktualisiert. Es wird in der Zieltabelle aber nicht gelöscht, also es ist keine vollständige "Synchronisation". Zur Ermittlung der Gleichheit zweier Zeilen dient (wo vorhanden) eine proprietäre UID, ansonsten inhaltlicher Vergleich aller Spalten. Das Einfügen bzw. Aktualisieren erfolgt aber nicht mit
SQL-Insert- oder
SQL-Update-Befehlen, sondern über die
API mit .Append bzw. .Edit. (Geht Append/Edit überhaupt mit einer
Query?)
Das sollte mit oben beschriebenen Vorgehen realisierbar sein.
Was ich mir noch an Alternativen überlegt habe, um um das .Open() herumzukommen:
- Aus den
Access-DBs auf den
SQL Server nicht direkt in die riesigen Originaltabellen kopieren, sondern erstmal in leere Dummy-Zieltabellen mit derselben Struktur, denn dann geht das .Open() ja schnell. Dann ein
SQL-
MERGE-Kommando absetzen, das jeweils die Dummytabelle in die Originaltabelle ein"merged" (oder Kombination aus INSERT und UPDATE). Dann ist
ADO außen vor und der Server macht die Arbeit selbst. Allerdings müsste ich dann die Identitätsprüfung der Zeilen in
SQL selbst formulieren, das dürfte auch haarig werden.
- Ginge sowas auch mit
Stored Procedures? Nur eine vage Idee.
Ja. Meine Devise war eigentlich immer: Was die Datenbank machen kann, lass die Datenbank machen, dafür ist sie da. Alles (über das Netzwerk) in den eigenen Arbeitspeicher holen, mit eigenem Programm verarbeiten und dann die Datenbank schreibenlassen, ist umständlich und aufwändig und niemals schneller als die Datenbank (auch wenn der Programmieraufwand in Delphi geringer erscheint).
Wenn die Daten nicht an einem Stück benötigt werden, sondern das Kopieren von A nach B auch in mehreren Schritten hintereinander (durchaus in einer Transaktion) erfolgen kann, dann verarbeite die Daten in einer Schleife. Gibt es einen eindeutigen Schlüssel (z. B. ID = 1:n), dann nimm immer ca. 10000 Sätze, also ID von 1 bis 10000, dann ID von 10001 bis 20000, ...
Auch wenn das funktioniert, bleibt dann immer noch das Performanceproblem...
Das liegt aber eventuell nur an der schier unüberschaubaren Datenmenge. Vermutlich haben beide Seiten nicht genug Arbeitsspeicher und müssen deshalb auf ihre Festplatten auslagern. Und die sind nun mal halt nicht unbedingt das schnellste Speichermedium. Wird virtueller Speicher genutzt (also Speicher, der physikalisch nicht vorhanden ist) wird's langsam.
Verarbeitungsmengen so wählen, dass der physikalische Speicher immer ausreicht, dann kann 1000 Mal ein Tausendstel durchaus schneller sein, als einmal alles, was ggfls. dann auch nur nach (gefühlten) Stunden mit 'ner Fehlermeldung scheitert.