Autor Beitrag
MitschL
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 211

Win 98 SE, Win 2000
D5 Pers, D6 Pers und D7 Pro
BeitragVerfasst: Fr 21.01.05 17:35 
Tach,

zu Beginn muß ich sagen, daß es hier um meine erste Applikation geht, die sich mit DBs rumzuschlagen hat, ohne diese auf irgendeiner Form zu präsentieren.

Ich muß für eine Exportfunktion aus 4 Tabellen notwendige Daten holen. Die Tabellen sind nicht verknüpft, obwohl es besser wäre. Sie besitzen verschiedene Sekundär-Indizes, die ich nicht kenne und sind IMHO zu breit. (Mich stört jede Tabelle, die mehr als 10 Spalten besitz, vor allem, wenn 90% davon alphanumerisch sind)
Über eine 25-spaltige Tabelle muß ich etwa 12 Spalten herauslesen; 25000 Datensätze und mehr. Hier finde ich dann Infos, um aus einer der drei anderen Tabellen (22, 64, 40 Spalten) einzelne Datensätze zu ziehen, wobei ich nur die Hälfte des Primärschlüssels in den Händen halte.

Aufgrund der Datenstruktur (2 auf Records basierende Klassen) lese ich also (, wie ich es zuvor schonmal in C++ gemacht hatte, )die Datensätze einzeln über Findfirst und Next eines TQuery-Objektes ein, schaue nach bestimmten Daten, wähle die passende weitere Tabelle und lese aus dieser den einen benötigten Datensatz. Für alles baue ich die SQL-Statements zusammen - für die drei Tabellen halt mit jedem Aufruf.

Ich halte das Ganze aber für grottenlahm. Für lächerliche 3000 Datensätze aus der ersten Tabelle mit weiteren 3000 Abfragen aus einer der anderen drei Tabellen braucht der Rechner (2GHz-System) über eine Minute! Sowas bin ich nicht gewohnt. :?

Was will ich? Mir genügt ein gedanklicher Ansatz, um das Ganze schneller zu machen. Immerhin steht den Daten eine Konvertierung nebst der Speicherung an und ich weis nicht, wie groß die Daten bei den Kunden werden können.
Vielleicht sind es nur Details, die ich zu machen brauch, oder ich sollte gar nicht so etwas machen, wie eine einfache TQuery-Komponente heranzuziehen, sondern etwas, daß in Delphi schneller arbeitet.

Aber: Ich darf nichts am Datenbank-Schema anfassen!

any kind of help is appreciated...

gegrüßt!

_________________
"Bloßes Ignorieren ist noch keine Toleranz." (Theodor Fontane)
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 21.01.05 19:57 
Eine klare Aussage zu deinem Problem zu machen fällt mir schwer.
Zunächst wäre interessant, um was für ein Datenbank-System es sich handelt.
Greifst du über die BDE und/oder ODBC auf die DB zu? Das macht es auch langsam.
Ein gut definiertes(optimiertes) SQL-Statement kann wunder wirken. Manchmal genügt es, Bedingungen in einer anderen Reihenfolge zu schreiben.
Hast du die Möglichkeit selber einen Index zu erstellen? Auch das kann sich auf die Performanz auswirken.
Kannst du mit einem Insert-Statement und einem Sub-Select die Daten in die neue Datenbank übertragen/konvertieren? Das spart dir das FindFirst und FindNext. Diese Dinge kosten auch viel Zeit.

Ich hoffe das ist Denkanstoß für dich.
MitschL Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 211

Win 98 SE, Win 2000
D5 Pers, D6 Pers und D7 Pro
BeitragVerfasst: Mo 24.01.05 09:29 
Moin,

ich Danke brav für die Antwort :)

jasocul hat folgendes geschrieben:
Eine klare Aussage zu deinem Problem zu machen fällt mir schwer.
Das ist mir bewußt, weswegen ich mit Denkanstößten mehr als zufrieden bin.
Zitat:

Zunächst wäre interessant, um was für ein Datenbank-System es sich handelt.
Greifst du über die BDE und/oder ODBC auf die DB zu? Das macht es auch langsam.
Mein kompletter Zugriff geschieht über die TQuery-Komponente. Ich habe lediglich das Verzeichnis angegeben und der Rest steht im SQL-Text. Die DB scheint vom Typ Paradox zu sein. Aufgrund der scheinbar notwendigen Vorbereitungen, eine ODBC-Verbindung zu etablieren - die ich nicht unternahm - gehe ich von der BDE aus.
Zitat:

Ein gut definiertes(optimiertes) SQL-Statement kann wunder wirken. Manchmal genügt es, Bedingungen in einer anderen Reihenfolge zu schreiben.
Krieg ich sowas nur durch Versuche raus? Reicht die Reihenfolge der Spalten oder bezieht sich das auf den Inhalt?
Zitat:

Hast du die Möglichkeit selber einen Index zu erstellen? Auch das kann sich auf die Performanz auswirken.
Da muß ich doch glatt mal schauen. Das Programm ist aber so ausgelegt, daß es nur die benötigten Spalten ausliest - eine variable Anzahl also - bei der ich befürchte, Indizes sind subotimal.
Zitat:

Kannst du mit einem Insert-Statement und einem Sub-Select die Daten in die neue Datenbank übertragen/konvertieren? Das spart dir das FindFirst und FindNext. Diese Dinge kosten auch viel Zeit.
Das mit dem Findnext irritiert mich ein wenig, sollte doch zu diesem Zeitpunkt das Result-Set feststehen. Ich habe deswegen den Cursor nicht mal mehr auf bidirektional, weil ich hoffte, wenn ich schon beim ersten Satz bin, sollte das Next schneller laufen.

Wie sieht es eigentlich aus, wenn ich mehrere Semikolon-separierte Statements mit einem mal abschicke? Geht das überhaupt über die TQuery-Komponente? Bei einer ODBC-Verbindung wirkt das ziemlich gut.

Zudem lese ich die Werte über die FieldByValue-Funktion aus. Sind hier andere Mechanismen schneller? Ich dürfte zwar eh jeden Wert einzeln brauchen, weil ich ja eigens erstellte Klassen nutze, aber es ist meißt schneller, wenn ich mir die Sachen aus einer Struktur lese, die wie eine Liste im Speicher/Buffer/sonstwo-außerhalb-einer-DB liegt.

Fragen über Fragen und schon jetzt ein großes Danke - beschäftige ich mich dadurch wenigstens anständig mit dem Thema. :)

gegrüßt!

_________________
"Bloßes Ignorieren ist noch keine Toleranz." (Theodor Fontane)
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mo 24.01.05 10:51 
Du nutzt TQuery. Das macht dich schonmal sympatisch :wink:

Die Strukturierung des SQL-Statements (Reihenfolge der Bedingungen, bei Joins auch die der Tabellen) musst du vermutlich ausprobieren. Ich kenne das Phänomen von Oracle, da dort, durch Umstellungen im Statement die Reihenfolge der benutzten Indexe beeinflusst wird. Je größer die erste Einschränkung ist, um so besser.

Ob die BDE Semikolon-Separierte Statments verarbeit weiß ich nicht.

Eine schneller Methode als FieldValues ist vermutlich Fields. Dafür musst du allerdings den Index des Feldes in der Tabelle kennen. Bei FieldValues übergibst du ja den Feldnamen. Die BDE dürfte sich dann selbst den Index raussuchen und das entsprechende Feld verwenden. Das könntest du der BDE dann sparen.

Ein paar Ideen zur Beschleunigung:
- Kannst du evtl. die SQL-Ergebnisse temporär Speichern und dann verwenden? Zum Zwischenspeichern TBatchMove verwenden. Danach mit der kleineren Zwischen-Tabelle arbeiten.
- Alle Anzeige-Elemente während der Übertragung ausschalten (DisableControls der TQuery).
- Möglichst jedes Try-Except vermeiden. Vor allem in Schleifen. Das sind echte Zeitfresser.
MitschL Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 211

Win 98 SE, Win 2000
D5 Pers, D6 Pers und D7 Pro
BeitragVerfasst: Mo 24.01.05 11:34 
Sei dir meines Dankes gewiß,

die TQuery kam mir aus zwei Gründen in den Sinn: Ich kenne Vergleichbares aus meiner C++-vergangenheit. Außerdem trenne ich gern Logik von Präsentation und da (- in der Delphi DE -) sind so viele Controls, die das gern verbinden.

die Reihenfolge der einschränkenden Parameter ist unter dem Gesichtspunkt der maximalen Einschränkung leider variabel. Ich kann lediglich sagen, daß ein bestimmter Parameter nicht am Anfang ist, während sich zwei weitere durchaus abwechseln könnten (ein Zeichen und ein Datum)

Das mit der Zwischenspeicherung werde ich mal versuchen, wobei ich noch schauen muß, wie ich an die Spalten-IDs komme. Immerhin lese ich die Namen zuvor aus einem konfigurierbaren String. So etwas wie ein GetColumnIndex scheint es nicht zu geben.

Anzeige-Elemente? Die Arbeit mit TQuery wird in einem separaten Thread für sich allein ausgeführt. Es gibt vom Programm aus lediglich eine Fortschrittsbalken und den berühmten Abbruch-Button. - oder meinst du was anderes?

Try-Except-Blöcke verwende ich sehr selten. Sie ermöglichen zu schnell ein unter-den-Tisch-kehren. Ich muß mir aber Disziplin bewahren. (ich kann mir aber gut vorstellen, daß das Thema: Nutzung von Try-Except schon so manche hitzige Diskussion eingeleutet hat. :) )

gegrüßt!

_________________
"Bloßes Ignorieren ist noch keine Toleranz." (Theodor Fontane)
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mo 24.01.05 12:18 
Das mit dem Spaltenindex habe ich nicht gut formuliert. Wenn du eine Tabelle öffnest, bekommst du die Felder in einer bestimmten Reihenfolge. Diese fängt bei 0 an zu zählen und geht bis Feld-Anzahl -1. Diesen Index solltest du verwenden. Das wirkt sich bei großen Datenmengen sicher aus.

Dein Fortschrittsbalken kstet auch Performance. Wenn du ihn wirklich benötigst, mache die Aktualisierung möglichst selten. Falls du die ProgressBar verwendest, musst du nur die Steps in akzeptablen Größen wählen. Z.B. alle 500 Datensätze. Dann brauchst du zwar eine weitere Zähl-Variable, aber jedes StepIt kostet mehr Zeit als ein Inc(i).

Try-Except kann Sinn machen. Man neigt dann aber zur Bequemlichkeit und findet seine eigenen Fehler nicht mehr. In der Anfangszeit von Delphi hatte ich mal einen Try-Except-Block in einer Schleife. Das war unterträglich. Eine gute Prüfung eingebaut und das ganze war um einen Faktor 8 schneller. Damals ging es auch um eine Datenübernahme.
MitschL Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 211

Win 98 SE, Win 2000
D5 Pers, D6 Pers und D7 Pro
BeitragVerfasst: Di 25.01.05 16:55 
OK.,

Zitat:
Das mit dem Spaltenindex habe ich nicht gut formuliert. Wenn du eine Tabelle öffnest, bekommst du die Felder in einer bestimmten Reihenfolge. Diese fängt bei 0 an zu zählen und geht bis Feld-Anzahl -1. Diesen Index solltest du verwenden. Das wirkt sich bei großen Datenmengen sicher aus.

Hm. Sowas hätte ich gern, wird doch aber nicht so von der TQuery abrufbar gehalten, oder etwa doch? Dann bräuchte ich mir nur einmal die Spalten-Indizes zu den Namen besorgen und das wär's. :lupe:

Die ProgressBar verschlingt nicht nennenswert Performance (hab ich schon getestet), weil diese über eine besondere Schnittstelle ihre Daten zwar erhält, diese aber nicht sehr häufig abruft. Diese Regelmäßigkeit richtet sich nach der Zahl der zu exportierenden Datensätze. (umgekehrt proportional, um genau zu sein)

gegrüßt!

_________________
"Bloßes Ignorieren ist noch keine Toleranz." (Theodor Fontane)
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Di 25.01.05 17:03 
Zum Beispiel:
ausblenden Delphi-Quelltext
1:
  vString := query1.Fields[0].AsString;					

Geht doch :wink:

Gilt natürlich nur für die im Query gewählten Felder. (* = alle. Aber das weißt Du ja)
MitschL Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 211

Win 98 SE, Win 2000
D5 Pers, D6 Pers und D7 Pro
BeitragVerfasst: Mi 26.01.05 11:14 
Hm,

ich hab aber nur die Spalten-Namen der Tabelle, nicht ihre Position, weil die sich zudem ändern kann.
Wenn ich Fields[0] mache, muß ich sicher sein, daß sich darunter stets die richtige Spalte befindet. Deswegen wäre so etwas wie ein

ausblenden Delphi-Quelltext
1:
c1I := query1.Fields.GetColumnIndexByName( 'MeineErsteSpalte' );					

und in der Schleife:

ausblenden Delphi-Quelltext
1:
result := query1.Fields[c1I].AsString;					

das Richtige für mich. Dann würde ich IMHO auf der sicheren Seite.

gegrüßt!

Moderiert von user profile iconraziel: Delphi-Tags hinzugefügt

_________________
"Bloßes Ignorieren ist noch keine Toleranz." (Theodor Fontane)
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mi 26.01.05 11:40 
Die Feld-Nr solltest du wie folgt herausbekommen:
ausblenden Delphi-Quelltext
1:
F_Nr := query1.FieldByName('FeldName').FieldNo;					
MitschL Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 211

Win 98 SE, Win 2000
D5 Pers, D6 Pers und D7 Pro
BeitragVerfasst: Mi 26.01.05 13:15 
Ähm,

hab' ich gerade probiert. Klappt nicht.
:gruebel: :les:
Aha! Das war klar.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
data := query1.FieldByName( 'col1' ).AsString;
// entspricht:
id := query.FieldByName( 'col1' ).FieldNo;
data := query1.Fields[id-1].AsString;
:hair:

Irgendwas ist immer. Ich werd mal noch das ein oder andere probieren und danke dir.

gegrüßt!

_________________
"Bloßes Ignorieren ist noch keine Toleranz." (Theodor Fontane)