Designproblem wegen Thread oder Datenbankviews



  • Moin!

    Seitdem endlich auch mal ordentlich Daten in der Datenbank sind, habe ich elendige Ladezeiten.
    Aktuelles Problemkind ist das Drucken, weil da mal eben 70 Querys über zig Tabellen laufen müssen. Das dauert insgesamt über 20 Sekunden. 😮
    Für einen Datensatz wohlgemerkt, ich habe noch nicht wieder versucht, eine Liste zu drucken.

    Nun hatte ich die Idee, das in einen Thread auszulagern.
    Das scheitert aber daran, dass alles sehr eng in meine Dokumentenstruktur eingeflochten ist. Das Drucken passiert im Basisdokument und die wirklich genutzten Funktionen stehen in den jeweils abgeleiteten Docs, die ihre jeweils geladenen Recordsets nutzen.
    Ich fürchte, ich habe keine Chance, das an einen Thread weiterzugeben, oder? 😕

    Die Alternative wären neue Views in der Datenbank, die auch wieder neue Recordsetklassen bedeuten. 🙄
    Und das ne ganze Menge... 😞

    Ich tendiere momentan zu den Views...

    Habt ihr irgendwelche Ideen oder Vorschläge, wie man das beschleunigen kann?
    Ich habe schon zig Doppelquerys rausgeworfen, aber nun ist da das Ende erreicht. Jede weitere Kürzung bedeutet "Datenverlust", weil diese dann nicht mehr gedruckt werden könnten. 😞

    Falls wieder jemand kommt mit "Nimm doch was anderes als CRecordset mit ODBC": Ja, wo ist denn das Tutorial, wie ich fertige Klassen umbiege? Und das bitte in KURZER Zeit! 😕



  • Hm kannst evtl. die Datenbank an sich optimieren? Gibt es bestimmte Tabellen, wo der Zugriff sehr oft ist? Lässt sich ja in den DB-System dann einstellen.
    Ein Thread würde das ja nicht wirklich schneller machen.

    Oder werden die Daten evtl. vorher schon benutzt, dass du sie dir da "merksts" um sie nicht wieder aus der DB abfragen zu müssen.


  • Mod

    Diese Queries in anderen Threads laufen zu lassen geht evtl. gar nicht, wenn die entsprechende ODBC Komponente nicht multithreading fähig ist.

    Wenn musst Du in dem Thread in jedem Fall eine neue Datenbankverbindung aufbauen. Dann sollte das auch gehen.

    Das ist der Grund warum ich ODBC nie verwendet habe. Grundsätzlich nur OLEDB!

    Und wie Palleon schon geschrieben hat: Ein Index an der ricthigen Stelle kann in der Geschwindigkeit Wunder wirken. Genau wie ein Index an der falschen Stelle eine Katastrophe ist.



  • Okay, hier rächt sich jetzt, dass ich nur einen Tag Datenbankschulung hatte. 🙄
    Ich habe in JEDER Tabelle eine ID, die Primary Key ist. Ist das automatisch auch gleich ein Index? Wenn nein, wäre es sinnvoll, den Index darüber zu legen? Ich greife in den allermeisten Fällen über die ID zu (also "where ID = ..."). 😕

    PS: Ich hatte gestern 110 Querys in gut 20 Sekunden und heute nach einiger Optimierung an der Aufruferei 70 in derselben Zeit.
    Ist der Fehler evtl. woanders? Die Queryzeiten sehen eigentlich gut aus, denk ich mal:

    0 ms
    0 ms
    656 ms
    0 ms
    0 ms
    0 ms
    0 ms
    0 ms
    0 ms
    515 ms
    672 ms
    610 ms
    0 ms
    0 ms
    0 ms
    16 ms
    625 ms
    281 ms
    0 ms
    0 ms
    0 ms
    859 ms
    31 ms
    0 ms
    797 ms
    0 ms
    0 ms
    0 ms
    0 ms
    0 ms
    0 ms
    797 ms
    0 ms
    0 ms
    0 ms
    750 ms
    0 ms
    0 ms
    15 ms
    0 ms
    516 ms
    31 ms
    547 ms
    719 ms
    641 ms
    16 ms
    593 ms
    0 ms
    188 ms
    0 ms
    0 ms
    0 ms
    0 ms
    391 ms
    0 ms
    0 ms
    16 ms
    547 ms
    0 ms
    16 ms
    0 ms
    0 ms
    515 ms
    94 ms
    15 ms
    0 ms
    407 ms
    563 ms
    890 ms

    Oder sind da welche dabei, die bei wenigen Daten (selten 100 in einer Tabelle) schon zu lang sind?



  • Für einen Primary Key wird automatisch ein Index angelegt, ja.
    Was für eine DBS benutzt du denn?
    Sind in deinen Abfrageb sehr viele JOINs usw.?

    Wie speicherst du die Daten zwischen? Nicht das auch noch viel Zeit beim Allokieren in deinem Programm draufgeht.



  • Pellaeon schrieb:

    Für einen Primary Key wird automatisch ein Index angelegt, ja.

    Puh, doch was gelernt. 🙂

    Was für eine DBS benutzt du denn?

    Microsoft SQL Server 2000 SP3 Desktop Edition (Ja, ich weiß es gibt ne neuere, aber wie kompatibel die ist, kann mir keiner 100%ig sagen...

    Sind in deinen Abfrageb sehr viele JOINs usw.?

    Im Gegenteil, bisher mache ich 99% ohne Views. Jedes Recordset ist eine Tabelle die sich dann den Rest "erfragt".
    Views wären jetzt mein Ansatz, um es schneller zu kriegen.

    Wie speicherst du die Daten zwischen? Nicht das auch noch viel Zeit beim Allokieren in deinem Programm draufgeht.

    Das läuft alles über lokale Recordsets in der jeweiligen Funktion.
    Ich fürchte, genau das ist es und forsche auch schon in der Richtung. Nur nach was muss man da suchen und wie wird es schneller? 😕



  • Wieviel Datensätze liefert denn eine Abfrage? Ist das sehr viel? Und speicherst du die dann in einem vector, oder wird das gleich weiter verarbeitet?



  • Also, in den Fällen liefert jede Abfrage nur einen Datensatz (weil ich auf eine bestimmte ID abfrage).
    Der Datensatz meldet sich dann beim Druckprogramm (ist eine Funktion in den Recordsets), läd ggf. noch abhängige Daten nach und veranlasst deren Weitergabe ans Druckprogramm und wird danach wieder vergessen.


  • Mod

    Wenn Du einen primären Schlüssel hast, dann ist dieser ID auch clustered und indiziert!

    Die Frage wäre: Benötigst Du die ganzen Queries einzeln, oder kann Dir das System die Daten einfacher liefern?
    Welchen Cursor Typ verwendest Du? Das hat immensen Einfluss auf die Geschwindigkeit!
    Hast Du mal den SQL Profiler mitlaufen lassen?

    Es ist in jedem Fall besser wenn man dem SQL Server weniger Anfragen stellt und möglichst viele Daten in einem Rutsch zurückbekommt (JOINs).
    Eine komplette komplexe Abfrage kann der SQL Server oft besser optimieren.



  • Martin Richter schrieb:

    Die Frage wäre: Benötigst Du die ganzen Queries einzeln, oder kann Dir das System die Daten einfacher liefern?

    Was wäre einfacher? Ich fand das bisher immer einfach. 😉

    Welchen Cursor Typ verwendest Du? Das hat immensen Einfluss auf die Geschwindigkeit!

    Ich verwende den Defaulttyp. Ich habe es aber eben mal mit CRecordset::forwardOnly versucht, da bekomme ich:
    Connection is busy with results for another hstmt

    Hast Du mal den SQL Profiler mitlaufen lassen?

    Nein, da ich nicht weiß, nach was ich gucken muss.

    Es ist in jedem Fall besser wenn man dem SQL Server weniger Anfragen stellt und möglichst viele Daten in einem Rutsch zurückbekommt (JOINs).
    Eine komplette komplexe Abfrage kann der SQL Server oft besser optimieren.

    Das hatte ich befürchtet. 😞



  • So, ich habe jetzt wieder an einer Stelle 2 von 3 Querys gespart und das hat nochmal 3 Sekunden gebracht.
    Es wird wohl wirklich auf die Views hinauslaufen. 🙄



  • Hast Du denn schon mal geprüft, ob es sich lohnen würde noch andere Spalten, als die Primary Keys, zu indizieren? Oftmals hat man doch solche Anfragen wie:
    SELECT idFoo FROM foo WHERE foo.foo_name = 'bar'.
    Dann ist es meist besser auch foo_name zu indidzieren. Oftmals sind auch temporäre Tabellen das Problem, die müssen erst von Hand indiziert werden.


  • Mod

    forwardonly ist aber der schnellste Cursor Typ!



  • Martin Richter schrieb:

    forwardonly ist aber der schnellste Cursor Typ!

    Ich weiß, den Tip hast du mir schon mal gegeben. 🙂
    Leider scheint der Einschränkungen zu haben, die dann die Meldung verursachen und solange ich nicht weiß, was da genau schief läuft, muss ich den Default verwenden.

    connan schrieb:

    Hast Du denn schon mal geprüft, ob es sich lohnen würde noch andere Spalten, als die Primary Keys, zu indizieren? Oftmals hat man doch solche Anfragen wie:
    SELECT idFoo FROM foo WHERE foo.foo_name = 'bar'.
    Dann ist es meist besser auch foo_name zu indidzieren.

    An der kritischen Stelle wird wirklich ausschließlich nach den IDs gefiltert. 🙂
    Die Filterung nach anderen Spalten ist so selten, dass sie sich nicht lohnt.

    Oftmals sind auch temporäre Tabellen das Problem, die müssen erst von Hand indiziert werden.

    Ich glaube, soetwas verwende ich nicht. 😕



  • estartu schrieb:

    Oftmals sind auch temporäre Tabellen das Problem, die müssen erst von Hand indiziert werden.

    Ich glaube, soetwas verwende ich nicht. 😕

    Vieleicht ist das dann eine Lösung für dein Problem. Man hat dadurch den Vorteil, dass man sich keine Ergebnisse aus der Datenbank zurückgeben lassen muss um nachher mit diesen Daten wieder eine Anfrage zu starten (was ich immer sehr nervig finde 😉 ). Inwieweit sich dadurch ein Geschwindigkeitsvorteil ergibt habe ich noch nicht geprüft, würde ich in Deinem Fall aber versuchen.
    Das Statement sieht folgendermaßen aus:

    temp. Tabelle erstellen:

    CREATE TEMPORARY TABLE tmp_foobar (SELECT idFoo FROM bar,foo WHERE bar.idFoo = foo.idFoo )
    

    temp. Tabelle benutzen:

    SELECT * FROM tmp_foobar
    

    temp. Tabelle indizieren:

    ALTER TABLE `tmp_foobar` ADD INDEX `tmp_foobar_FKIndex1` ( `idFoo` )
    

    temp. Tabelle löschen:

    DROP TEMPORARY TABLE tmp_foobar
    

    Eine temporäre Tabelle an der richtigen Stelle kann das Leben ungemein vereinfachen 😉



  • Erst macht es Probleme und dann soll es die lösen... 😕
    Versteh einer diese Software. 😉

    Danke für die Befehlssammlung. 👍

    Wenn ich so eine Tabelle innerhalb einer Transaktion erstelle und wieder lösche, dann hat die ja kein anderer gesehen, oder?
    Mit Transaktionen verheddere ich mich aber immer schnell, gibt es da einen besseren Trick für die Tabellennamen?
    Weil es muss möglich sein, dass mehrere Leute gleichzeitig drucken können.

    Dadrüber muss ich mal nachdenken...



  • Diese Tabellen sind nur für den Sichtbar der sie erstellt, keine Sorge.

    Edit: Sofern jeder auch seine eigene Verbindung zu Datenbank hat!!


  • Mod

    Tabellennamen mit tmp voranzustellen ist nicht das was ich unter temporären Tabelen verstehe, die sich vor allem auch selbst wieder aufräumen.

    Siehe:
    Abschnitt Temporary Tables in
    http://msdn2.microsoft.com/en-us/library/aa258255(SQL.80).aspx

    Prefix local temporary table names with single number sign (#table_name), and prefix global temporary table names with a double number sign (##table_name).

    Temporary tables are automatically dropped when they go out of scope, unless explicitly dropped using DROP TABLE:

    A local temporary table created in a stored procedure is dropped automatically when the stored procedure completes. The table can be referenced by any nested stored procedures executed by the stored procedure that created the table. The table cannot be referenced by the process which called the stored procedure that created the table.

    All other local temporary tables are dropped automatically at the end of the current session.

    Global temporary tables are automatically dropped when the session that created the table ends and all other tasks have stopped referencing them. The association between a task and a table is maintained only for the life of a single Transact-SQL statement. This means that a global temporary table is dropped at the completion of the last Transact-SQL statement that was actively referencing the table when the creating session ended.
    A local temporary table created within a stored procedure or trigger can have the same name as a temporary table created before the stored procedure or trigger is called. However, if a query references a temporary table, and two temporary tables with the same name exist at that time, it is not defined which table the query is resolved against. Nested stored procedures can also create temporary tables with the same name as a temporary table created by the stored procedure that called it.



  • Hey Danke 😃 wieder was gelernt, hab ich allerdings so noch nie gesehen. Bei mir läuft aber auch ein mysql-Server 🙄 . Heißt das jetzt eigentlich, daß es beim microsoft-SQL-Server nur so funktioniert (mit #,##)?


Log in to reply