Multithread-Delphi-Datenbankanwendung schlägt mit großen Datenmengen fehl

8

Überblick über die Anwendung:
Ich habe eine Delphi-Anwendung, die es einem Benutzer ermöglicht, eine Anzahl von Abfragen zu definieren und sie gleichzeitig über mehrere MySQL-Datenbanken auszuführen. Die Anzahl der Threads, die gleichzeitig ausgeführt werden können (die der Benutzer festlegen kann), ist begrenzt. Der Benutzer wählt die auszuführenden Abfragen und die Systeme aus, auf denen die Abfragen ausgeführt werden sollen. Jeder Thread führt die angegebene Abfrage auf dem angegebenen System mit einer TADOQuery-Komponente aus.

Beschreibung des Problems:
Wenn die Abfragen eine geringe Anzahl von Datensätzen abrufen, funktioniert die Anwendung ordnungsgemäß, auch wenn viele Threads (bis zu etwa 100) gesendet werden. Die Anwendung kann auch eine größere Anzahl von Datensätzen verarbeiten (150.000+), solange nur wenige Threads (bis zu etwa 8) gleichzeitig ausgeführt werden. Wenn der Benutzer jedoch mehr als zehn Abfragen gleichzeitig ausführt (d. H. Mehr als zehn Threads) und jeder Thread ungefähr 150.000 Datensätze abruft, erhalten wir Fehler. Hier sind die spezifischen Fehlermeldungen, die wir bisher gefunden haben:

a: Not enough storage is available to complete this operation
b: OLE error 80040E05
c: Unspecified error
d: Thread-Erstellungsfehler: Not enough storage is available to process this command
e: Object was open
f: ODBC Driver does not support the requested properties

Offensichtlich beruhen die Fehler auf einer Kombination von Faktoren: Anzahl der Threads, Menge der pro Thread abgerufenen Daten und möglicherweise der Konfiguration des MySQL-Servers.

Die Hauptfrage ist wirklich, warum treten die Fehler auf? Ich schätze, dass es in gewisser Weise mit Ressourcen zu tun hat, aber angesichts der unterschiedlichen Fehler, die zurückgegeben werden, würde ich gerne wissen, warum genau die Fehler auftauchen. Sind es beispielsweise Ressourcen auf dem PC oder etwas, was mit der Konfiguration des Servers zu tun hat.

Die nächste Frage lautet: Was können wir tun, um die Probleme zu vermeiden? Derzeit drosseln wir die Anwendung, indem wir die Anzahl der Threads verringern, die gleichzeitig ausgeführt werden können. Wir können den Benutzer nicht zwingen, weniger Datensätze abzurufen, da die Abfragen vollständig benutzerdefiniert sind, und wenn sie 200.000 Datensätze abrufen möchten, dann liegt das an ihnen, also können wir nicht viel tun, was diese Dinge betrifft. Realistischerweise möchten wir die Geschwindigkeit der Anwendung nicht drosseln, da die meisten Benutzer kleine Datenmengen abrufen und wir die Anwendung nicht zu langsam für die Verwendung machen möchten, und obwohl die Anzahl der Threads dies kann Wenn wir vom Benutzer geändert werden, gehen wir lieber zur Wurzel des Problems und versuchen, es zu beheben, ohne sich darauf verlassen zu müssen, die Konfiguration ständig zu optimieren.

    
Jeedee 01.03.2011, 17:41
quelle

4 Antworten

5

Es sieht so aus, als würden Sie viele Daten clientseitig laden. Sie müssen möglicherweise im Clientspeicher zwischengespeichert werden (insbesondere wenn Sie bidirektionale Cursor verwenden) und in einer 32-Bit-Anwendung, die nicht ausreichen kann, abhängig von der durchschnittlichen Zeilengröße und der Effizienz der Bibliothek zum Speichern von Zeilen. Normalerweise ist es am besten, wenn Sie die Datenbank direkt auf dem Server ausführen, ohne Daten auf den Client zu laden. Normalerweise haben Datenbanken ein effizientes Cachesystem und können Daten auf die Festplatte schreiben, wenn sie nicht in den Speicher passen. Warum rufen Sie 150000 Zeilen gleichzeitig ab? Sie können einen Mechanismus verwenden, um Daten nur dann zu übertragen, wenn der Benutzer tatsächlich auf sie zugreift (Art von Paging durch Daten), um große Teile des "verschwendeten" Speichers zu vermeiden.

    
user160694 01.03.2011, 19:49
quelle
4

Das macht vollkommen Sinn (die Tatsache, dass Sie Probleme haben, nicht die spezifischen Fehler). Denken Sie darüber nach - Sie haben das Äquivalent von 10 Datenbankverbindungen (1 pro Thread), die jeweils 150.000 Datenzeilen (1.500.000 Zeilen insgesamt) über eine einzige Netzwerkverbindung empfangen. Selbst wenn Sie keine clientseitigen Cursor verwenden und die Zeilen klein sind (nur ein paar kleine Spalten), ist dies ein RIESIGER Datenfluss über eine einzelne Netzwerkschnittstelle und ein großer Treffer im Speicher des Clientcomputers.

Ich vermute, dass die Fehlermeldungen inkorrekt sind, genauso wie Sie manchmal eine Zugriffsverletzung haben, die durch eine Speicherüberschreibung an einem anderen Codeort verursacht wird.

    
Ken White 01.03.2011 20:21
quelle
0

Abhängig von Ihrem DBMS können Sie zur Lösung des Problems die LIMIT / TOP-Klausel sql verwenden, um die Menge der zurückgegebenen Daten zu begrenzen.

    
Simon 03.03.2011 00:43
quelle
0

Dinge, die ich tun würde:

  • schreiben Sie eine sehr einfache Testanwendung, die nur die notwendigen Teile der Verbindungs- / Abfrageerstellung (mit Threads) verwendet, dies würde alle Nebeneffekte eliminieren, die durch andere Teile Ihrer Software verursacht werden

  • verwenden eine andere Datenbankzugriffsebene anstelle von ODBC, um herauszufinden, ob der ODBC-Treiber die Ursache des Problems ist

  • Es sieht so aus, als wäre die Speicherbelegung kein Problem, wenn die Anzahl der Threads niedrig ist - um dies zu überprüfen, würde ich auch den Speicherbedarf der Datensätze messen / berechnen, vergleichen Sie sie mit der Speichernutzung der Anwendung in das Betriebssystem. Wenn beispielsweise Tests zeigen, dass vier Threads problemlos 1,5 GB Gesamtdaten problemlos abfragen können, aber zehn Threads mit weniger als 0,5 GB Gesamtdaten fehlschlagen, würde ich sagen, dass es sich um ein Threading-Problem handelt.

mjn 03.03.2011 07:49
quelle

Tags und Links