[c++] Ewig lange traversierung durch "SQL"-Spalten
-
Hey!
Kurze Vorinformationen: Programmierumgebung: Borland Developer Studio 2006 C++ Builder
(Sehr ähnlich zu Borland C++ Builder [eine der Vorversionen])In einem großen Projekt gibt es eine Datenbank-Anbindung. Die Datenbank ist über MySQL realisiert und funktioniert schon seit geraumer Zeit wunderbar. Leider ist jetzt aufgefallen, dass das Handling der Tabellen bei den Datenmassen sehr lange dauert. Ich habe die Frage ob es bessere Zugriffsmöglichkeiten gibt, als die, welche ich nutze. Kurz zur Erläuterung:
Es gibt eine (die, welche die meiste Auslesezeit braucht) Tabelle, welche 1025 Spalten enthält. Die erste ist der Index, der Rest besteht aus Integern.
Die Titel lauten wie folgt: "SpectrumNr", "count0", "count1", ..., "count1023"Bisher realisiere ich das Auslesen über ein TQuery-Objekt und eine Schleife wie folgt:
TQuery* DatabaseQuery... ... DatabaseQuery->SQL->Clear(); DatabaseQuery->SQL->Add("SELECT * FROM spectrumraw1024 WHERE SpectrumNr = 12345"); DatabaseQuery->Open(); for (int i = 0; i < 1024; i++) { integerArray[i] = DatabaseQuery->FieldByName("count" + IntToStr(i))->AsInteger; } DatabaseQuery->Close();
Leider benötigt diese Routine mehr als eine halbe Sekunde für das Auslesen eines Datensatzes. Da aber etwa 1000 Datensätze gelesen werden müssen ist das nicht akzeptabel. Das selbige Auslesen aus kommagetrennten Dateien verrichtet alle 1000 Datensätze in einer Sekunde!
Es muss also möglich sein aus der Datenbank, welche nunmal diese Struktur unabänderbar besitzt, ebenso schnell auszulesen... Das Problem scheint in der horizontalen Traversierung (durch die Spalten rennen) zu liegen. Ich habe es mit ein paar der von TQuery angebotenen Methoden und Strukturen, wie TFields oder TFieldList ausprobiert, aber jedes lieferte die selbe lange Wartezeit.
Falls es aus technischen Gründen doch nicht möglich sein sollte die horizontale Traversierung schneller durchzuführen würde ich mich auch damit zufrieden geben, wenn die Einträge als Integerfelder irgendwo an einem für mich auffindbaren Speicher hintereinander weggeschrieben wären, nach dem Ausführen des SQL-Befehls, sodass ich sie auf direkt (meinetwegen über Hardware-Methoden) zugreifen kann. Leider habe ich bisher keine Möglichkeit gefunden dies zu bewerkstelligen!
Hat jemand eine Idee? Gibt es für Ergebnisse möglichkeiten der strichpunktgetrennten AnsiString-Ausgabe? Irgendwas anderes, womit ich schneller arbeiten könnte?Grüße!
Michael
-
Vielleicht ist der Zugriff über den Index schneller als über FieldByName. Musst du mal ausprobieren.
for (int i = 0; i < DatabaseQuery->FieldCount; i++) integerArray[i] = DatabaseQuery->Fields->Fields[i]->AsInteger;
-
ich würde nicht jeden Satze einzeln per SQL einlesen, sondern ALLE Sätze (also ohne die WhereKlausel)
Und dann in der Rückgabemenge die enstprechenen Sätze herauslesen.
Dies machen wir immer so, und geht um ein vielfaches schnellerGruß
Wes
-
Wesley schrieb:
ich würde nicht jeden Satze einzeln per SQL einlesen, sondern ALLE Sätze (also ohne die WhereKlausel)
Und dann in der Rückgabemenge die enstprechenen Sätze herauslesen.
Dies machen wir immer so, und geht um ein vielfaches schnellerGruß
WesÜberlesen ist meiner Erfahrung nach nur schneller, wenn die Where-Bedingung nicht einem Suchindex entspricht. Ist ein passender Index vorhanden, dann ist die Where-Bedingung schneller. (Bei Oracle ist das auf jeden Fall so.)
-
Nur aus Neugier: wie lange braucht Zeile 7, und wie lange Zeilen 9-11?
-
Das heraussuchen der Resultate aus der Datenbank liegt in einem wirklich akzeptablen Zeitrahmen. Deswegen ist das von der Struktur her auch indiskutabel.
Es geht NUR um das rausholen aus dem Ergebnis-Array in ein Integer-Array!
-
Noch einmal detailliert:
DatabaseQuery->SQL->Clear(); DatabaseQuery->SQL->Add("SELECT * FROM spectrumraw1024 WHERE SpectrumNr = 12345"); DatabaseQuery->Open();
das geht wunderbar schnell und braucht deshalb nicht geändert werden...
for (int i = 0; i < 1024; i++) { integerArray[i] = DatabaseQuery->FieldByName("count" + IntToStr(i))->AsInteger; }
Ist der teil der zu lange benötigt. Offensichtlich ist es die Funktion FieldByName, aber EBENSO (!!!) der direkte Zugriff über Fields[i], welche zu viel Zeit beanspruchen...
-
ACHTUNG!
Ich nehme meine letzten Aussagen komplett zurück!!Der Teil, welcher mehr als eine halbe Sekunde in Anspruch nimmt ist:
DatabaseQuery->Open();
Ich habe mich vertan und das garnicht in betracht gezogen!
Hat jemand eine Idee?Michael C. schrieb:
Noch einmal detailliert:
DatabaseQuery->SQL->Clear(); DatabaseQuery->SQL->Add("SELECT * FROM spectrumraw1024 WHERE SpectrumNr = 12345"); DatabaseQuery->Open();
das geht wunderbar schnell und braucht deshalb nicht geändert werden...
for (int i = 0; i < 1024; i++) { integerArray[i] = DatabaseQuery->FieldByName("count" + IntToStr(i))->AsInteger; }
Ist der teil der zu lange benötigt. Offensichtlich ist es die Funktion FieldByName, aber EBENSO (!!!) der direkte Zugriff über Fields[i], welche zu viel Zeit beanspruchen...
-
Hallo
Michael C. schrieb:
ACHTUNG!
Ich nehme meine letzten Aussagen komplett zurück!!Der Teil, welcher mehr als eine halbe Sekunde in Anspruch nimmt ist:
DatabaseQuery->Open();
Ich habe mich vertan und das garnicht in betracht gezogen!
Hat jemand eine Idee?Wenn es nun wirklich der Datenbankzugriff selber ist dann kannst du von der Seite aus nicht viel machen. Deine Optionen sind
- Datenbankkonzept ändern, so das Index auf die WHERE-Spalte liegt oder das weniger Spalten ausgelsen werden müßen
- eine schnellere Datenbank bzw. Datenbank-Client nehmen. Es wird nicht ganz klar wie du genau auf MySQL zugreifst. Wenn du zum Beispiel ODBC nimmst solltest du besser direktere Zugriffe benutzen, um schlimmsten Fall die MySQL-C-API.
- Die Wartezeit akzeptieren und entsprechend dem User anzeigen das der nicht denkt das Programm sei eingefroren
- Die Abfrage in einen Thread auslagern und das Ergenis zeitversetzt auswerten und anzeigenbis bald
akari
-
Es ist unmöglich die Datenbankstruktur zu verändern, da andere Systeme auf der selben Datenkbank beruhen und Daten verändern können, welche ich leider nicht in der Hand habe.
Ja, ich mache den ganzen Zugriff über ODBC. Wie meinst du das mit dem direkteren Weg? Klar, nicht über ODBC, aber auch nicht über die MySQL-Api... Also dann?
Ich bin für jegliche Hilfe offen!Grüße!
Michael
-
Evtl mal das http://www.da-soft.com/index.php?option=com_content&task=view&id=45&Itemid=145 austesten müsste alle mal schneller sein als über eine lahme ODBC Verbindung.
-
Ok, diese Thema kann geschlossen werden! Danke für die Hilfe!