Jeena Paradies: ein MySQL-Query dauert zu lange

Hallo,

Ich habe meine Datenbank schön normalisiert aber dadurch wird das ganze unter mysql4 sehr sehr langsam. Um das eine Query zu bekommen dauert es über 42 sekunden auf dem Server im Internet mit MySQL 4. Zu Hause auf meinem MacBook mit MySQL 5 dauert genau das gleiche nur etwa 0.22 Sekunden. ich kann zwar auf MySQL5 auf dem Server upgraden, weiß aber dann trotzdem nicht so wirklich ob das Query so optimal ist. Außerdem könnte man da einiges von den 3599 Ergebniszeilen weglassen, nur weiß ich nicht wie ich das machen soll. Erst mal schreibe ich mal auf wie die Datenbank aufgebaut ist:

teams:            |  id       |  name
team_to_division: |  team_id  |  division_id
divisions:        |  id       |  name         |  sport_id

Bisher habe ich so die ganzen Namen abgefragt:

SELECT teams.id, teams.name  
FROM teams  
LEFT JOIN team_to_division  
 ON teams.id = team_to_division.team_id  
LEFT JOIN divisions  
 ON team_to_division.division_id = divisions.id  
WHERE divisions.sport_id = 1;

Wobei das zwar funktioniert aber ich nicht wirklich weiß ob das alles so sinnvoll mit dem LEFT JOIN ist, das kam eher durch ausprobieren raus als durch Wissen.

Es kommen dabei aber auch sehr viele Daten raus, bisher 3599, wobei die meisten gar nicht benötigt werden. Ich könnte nämlich noch davor herausfinden welche divisions überhaupt gebraucht werden. Das würde ich dann als Array aus division_id(s) bekommen, z.B. [23, 123, 42, 23, 63, 311, 312]

Das Problem ist jetzt, ich hab keinen blassen Schimmer, wie ich das alles Geschwindigkeitsmäßig so schnell wie möglich machen kann, denn genau diese Daten werden sehr oft abgefragt. Kann mir jemand ein paar Tipps geben?

Grüße
Jeena Paradies

--
LoadRemoteHTML() - Daten einfach nachladen | Jlog | Gourmetica Mentiri
  1. Hi,

    Wobei das zwar funktioniert aber ich nicht wirklich weiß ob das alles so sinnvoll mit dem LEFT JOIN ist, das kam eher durch ausprobieren raus als durch Wissen.

    ich persönlich nutze die JOIN-Syntax nur dann, wenn ich einen Outer-Join habe. Ansonsten tut es auch ein Select über mehrere Tabellen mit entsprechenden WHERE-Bedingungen.

    Das würde ich dann als Array aus division_id(s) bekommen, z.B. [23, 123, 42, 23, 63, 311, 312]

    Ergo benötigst Du auf (mindestens) dieser Spalte einen Index. Es ist überlegenswert, diesem Index sekundär die Spalte team_id hinzuzufügen; das könnte den anschließenden SELECT BY ROWID auf die Tabelle sparen. Die beiden id-Spalten sind jeweils als Identifier gekennzeichnet?

    Das Problem ist jetzt, ich hab keinen blassen Schimmer, wie ich das alles Geschwindigkeitsmäßig so schnell wie möglich machen kann, denn genau diese Daten werden sehr oft abgefragt. Kann mir jemand ein paar Tipps geben?

    Ergänze das Statement durch ein vorhergehendes EXPLAIN, dann erhältst Du den Ausführungsplan der MySQL-DB. PhpMyAdmin ist hier sehr hilfreich.

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hallo Cheatah,

      ich persönlich nutze die JOIN-Syntax nur dann, wenn ich einen Outer-Join habe. Ansonsten tut es auch ein Select über mehrere Tabellen mit entsprechenden WHERE-Bedingungen.

      das tut weh. Nein, das ist keine gute Idee. Eine Idee aus dem letzten Jahrtausend, als es noch antiquierte DBMSe gab, die die JOIN-Syntax nicht verstanden bzw. nur die eigene proprietäre JOIN-Syntax. Solchen Systemen kommt heute keine Bedeutung mehr zu. Saubere Join-Syntax liefert viel verständlichere Statements als JOIN-Bedingungen mit der WHERE-Klausel zu verquicken. Du solltest Deine Einstellung ändern.

      Das würde ich dann als Array aus division_id(s) bekommen, z.B. [23, 123, 42, 23, 63, 311, 312]
      Ergo benötigst Du auf (mindestens) dieser Spalte einen Index.

      Das Problem ist jetzt, ich hab keinen blassen Schimmer, wie ich das alles Geschwindigkeitsmäßig so schnell wie möglich machen kann, denn genau diese Daten werden sehr oft abgefragt. Kann mir jemand ein paar Tipps geben?

      Jeena:
      Aus welchem Grund LEFT JOIN. Benötigst Du alle Mannschaften, auch wenn sie keinen Divisions zugeordnet sind? Fehlen Dir wirklich Datensätze, wenn Du zwei INNER JOINS verwendest?

      Rouvens Einführung Joins gibt Dir übrigens den Tipp mit der Tabelle anzufangen, die die wenigsten Werte hat, d.h. in Deinem Fall ganz bestimmt die divisions.

      Freundliche Grüße

      Vinzenz

      1. Hi,

        das tut weh. Nein, das ist keine gute Idee. Eine Idee aus dem letzten Jahrtausend, als es noch antiquierte DBMSe gab, die die JOIN-Syntax nicht verstanden bzw. nur die eigene proprietäre JOIN-Syntax. Solchen Systemen kommt heute keine Bedeutung mehr zu. Saubere Join-Syntax liefert viel verständlichere Statements als JOIN-Bedingungen mit der WHERE-Klausel zu verquicken. Du solltest Deine Einstellung ändern.

        welche dermaßen immensen Vorteile, dass Du eine Änderung meiner Einstellung(?) empfiehlst, siehst Du in der JOIN-Syntax? Lesbarkeit ist als Argument ungültig, denn eben gerade wegen der Lesbarkeit empfehle ich den Weg über die WHERE-Clause.

        Cheatah

        --
        X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
        X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes
        1. Hallo Cheatah,

          welche dermaßen immensen Vorteile, dass Du eine Änderung meiner Einstellung(?) empfiehlst, siehst Du in der JOIN-Syntax? Lesbarkeit ist als Argument ungültig, denn eben gerade wegen der Lesbarkeit empfehle ich den Weg über die WHERE-Clause.

          dann haben wir unvereinbare Standpunkte.

          Ich finde die Aufteilung in die bedeutungstragenden Bestandteile unverzichtbar. Es macht für mich einen riesigen Unterschied, ob eine bestimmte Bedingung zwei Tabellen miteinander verknüpft oder ob eine bestimmte Bedingung die Ergebnismenge einschränkt. Wenn Du diesen Unterschied nicht sehen kannst oder willst, ist das Deine Sache. Ich sehe diesen Unterschied, in meinen Statements sieht man diesen Unterschied.

          Freundliche Grüße

          Vinzenz

          1. Hi,

            dann haben wir unvereinbare Standpunkte.

            offenbar, was ja zum Glück nichts Schlimmes sein muss :-)

            Ich finde die Aufteilung in die bedeutungstragenden Bestandteile unverzichtbar. Es macht für mich einen riesigen Unterschied, ob eine bestimmte Bedingung zwei Tabellen miteinander verknüpft oder ob eine bestimmte Bedingung die Ergebnismenge einschränkt. Wenn Du diesen Unterschied nicht sehen kannst oder willst, ist das Deine Sache.

            Ich sehe zwar (natürlich) den Unterschied, aber nicht ein, warum dieser im Statement sichtbar sein sollte. Bei mir liegt der Fokus auf Optimierung der Ausführung, was oft genug auch das Auslagern eines Joins in z.B. ein Subselect zur Folge hat - damit ist die von Dir angestrebte Trennung schon mal nicht mehr möglich. Aber vielleicht kannst Du mich überzeugen?

            Cheatah

            --
            X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
            X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
            X-Will-Answer-Email: No
            X-Please-Search-Archive-First: Absolutely Yes
      2. yo Vinz,

        Eine Idee aus dem letzten Jahrtausend, als es noch antiquierte DBMSe gab, die die JOIN-Syntax nicht verstanden bzw. nur die eigene proprietäre JOIN-Syntax. Solchen Systemen kommt heute keine Bedeutung mehr zu.

        mal davon abgesehen, dass ich dir zustimme, die JOINS sauber zu implentieren und Cheatah zu überzeugen per definition wohl unmöglich ist, haben solche systeme aber auch heute noch eine bedeutung. oracle 8 kann keine ANSI JOIN Syntax und diese version (inklusive alle niedrigeren) ist sehr wohl noch im betrieb.

        Ilja

  2. yo,

    zusätzlich zu dem gesagten (vor allem geeignete indexe setzen), kannst du die division tabelle weiter einschränken:

    code...
    WHERE divisions.sport_id = 1
    AND divisions.id IN (23, 123, 42, 23, 63, 331, 312)

    Ilja