Felix Riesterer: Performance bei Joins

Liebe Mitlesende,

ich habe mich ganz neu in SQL eingearbeitet und stehe nun vor einem Performance-Problem. Ohne Joins geht eine Abfrage recht schnell (gefühlte halbe Sekunde), mit zwei Joins dazu aber fast fünfmal so lang. Hier meine Query:

SELECT  
    schueler.SchuelerID,  
    schueler.SchuelerName,  
    schueler.SchuelerVorname,  
    klassen.KlassenName  
FROM schueler  
    LEFT JOIN klassenlisten  
        ON schueler.SchuelerID=klassenlisten.SchuelerID  
    LEFT JOIN klassen  
        ON klassenlisten.KlassenID=klassen.KlassenID  
ORDER BY  
    schueler.SchuelerName,  
    schueler.SchuelerVorname

Da das Kapitel Joins für mich noch brandneu ist, bin ich froh, dass ich zumindest alle meine Daten aggregieren kann; über Performance konnte ich mir bisher noch keine Gedanken machen - bis jetzt jedenfalls, wo mir der Zeitunterschied deutlich (und unangenehm) auffällt.

Wer weiß Rat, wie ich das optimieren kann?

Liebe Grüße,

Felix Riesterer.

--
ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  1. Hi,

    Wer weiß Rat, wie ich das optimieren kann?

    Indizes auf den Verknüpfungsspalten.

    cu,
    Andreas

    --
    Warum nennt sich Andreas hier MudGuard?
    O o ostern ...
    Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
    1. Lieber MudGuard,

      Indizes auf den Verknüpfungsspalten.

      das war eben zu kurz, um mir weiterzuhelfen.

      Inwiefern sind denn meine ON-Statements keine "Verknüpfungsspalten"? Und inwiefern sind es keine Indices?

      Liebe Grüße,

      Felix Riesterer.

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Hallo Felix,

        Indizes auf den Verknüpfungsspalten.
        das war eben zu kurz, um mir weiterzuhelfen.

        Stichwort Index: wie wäre es mit einem kurzen Blick ins Handbuch?

        Inwiefern sind denn meine ON-Statements keine "Verknüpfungsspalten"? Und inwiefern sind es keine Indices?

        Nur weil Du Spalten zur Verknüpfung verwendest, wird deswegen noch lange kein Index für diese Spalten angelegt. Das musst Du schon selbst tun, im CREATE-TABLE- bzw. jetzt im ALTER-TABLE-Statement oder eben einem CREATE-INDEX-Statement. Einen Index bekommt man natürlich nicht umsonst, daher ist es *nicht* sinnvoll, auf alle Spalten Indexe zu setzen.

        Abgesehen davon:
        Gibt es Schüler, die auf keiner Klassenliste stehen?
        Gibt es Klassenlisten, die keiner Klasse zugeordnet sind?

        Für jede Frage, die Du mit "Nein" beantwortest, solltest Du den LEFT JOIN durch einen INNER JOIN ersetzen.

        Freundliche Grüße

        Vinzenz

        1. Lieber Vinzenz,

          Nur weil Du Spalten zur Verknüpfung verwendest, wird deswegen noch lange kein Index für diese Spalten angelegt. Das musst Du schon selbst tun

          ja, was genau ein Index ist, und wo ich ihn einsetzen muss, ist mir noch nicht klar. Das steht jetzt auf meiner To-Do-Liste, damit ich das lerne. Vielen Dank für den Anstoß dazu!

          Einen Index bekommt man natürlich nicht umsonst, daher ist es *nicht* sinnvoll, auf alle Spalten Indexe zu setzen.

          Das leuchtet mir ein.

          Abgesehen davon:
          Gibt es Schüler, die auf keiner Klassenliste stehen?
          Gibt es Klassenlisten, die keiner Klasse zugeordnet sind?

          Für jede Frage, die Du mit "Nein" beantwortest, solltest Du den LEFT JOIN durch einen INNER JOIN ersetzen.

          Die verschiedenen Joins sind mir auch noch nicht 100%ig klar. Aber in diesem speziellen Fall kann ich die erste Frage mit "ja", die zweite Frage dagegen mit "nein" beantworten. Also ändere ich das zu einem INNER JOIN.

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
          1. Hallo Ingrid,

            da habe ich vergessen mich zu bedanken. Also:

            Vinzenz, ganz herzlichen Dank!

            Liebe Grüße,

            Felix Riesterer.

            --
            ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
          2. Hallo,

            ja, was genau ein Index ist, und wo ich ihn einsetzen muss, ist mir noch nicht klar.

            ein Index ist eine Verwaltungsstruktur, die Suche und Sortieren ungemein beschleunigt (sortierte Ausgabe ist typischerweise eine In-Order-Traversierung des Baumes).

            Dadurch können die relevanten Datensätze, die sich bei einem Equijoin (d.h. einem Join mit einer Gleichheitsbedingung) ergeben, sehr schnell ermittelt werden. Ansonsten bleibt dem DBMS nicht viel mehr übrig als das kartesische Produkt der beteiligten Tabellen durchzuarbeiten, d.h. bei k Schülern, l Klassenlisten und m Klassen müssen k*l*n-Kombinationen durchgetestet werden.

            Ähnlich gilt für die Suche: kein Index, sequentielle Suche und im Schnitt n/2 Schritte, bis der Datensatz gefunden wird. Bei 1 Milliarde Datensätzen wären dies 500 Millionen Suchoperationen und im schlimmsten Fall eben eine Milliarde Suchoperationen. Selbst bei einem Binärbaum wäre der Datensatz in maximal 30 Suchoperationen gefunden. Mehr zu den in DBMS üblichen B-Trees findest Du in Wikipedia.

            Die verschiedenen Joins sind mir auch noch nicht 100%ig klar.

            Du kennst unsere Join-Artikel?

            Freundliche Grüße

            Vinzenz

            1. Lieber Vinzenz,

              vielen Dank für Deine Erläuterungen. Sie helfen mir beim tieferen Verständnis.

              Du kennst unsere Join-Artikel?

              ja, ich habe auch schon angefangen, sie zu lesen und ein bisschen davon habe ich sogar verstanden (daher mein bisheriger Stand der Query). Aber da ich noch ebensosehr damit beschäftigt bin, meine DB sinnvoll zu konzipieren, und da ich das Zusammenwirken dieser Struktur und der mit SQL möglichen Abfragen erst begreifen muss, lerne ich eben auf diesem Wege, wie ich meine gesamte Applikation überhaupt gestalten muss, damit sie das tut, was ich will.

              Die genannten Artikel geben für meinen momentanen Kenntnisstand nur sehr ungefähre (sprich: für mich noch nicht sofort umsetzbare) Hinweise, wie ich _meine_ DB anzulegen habe bzw. sollte. Dass dann die Join-Techniken nur eine Art Krönung eines tieferliegenden (Verständnis-)Problems bilden, kannst Du Dir vielleicht ausmalen... ;-)

              Trotzdem vielen Dank für Deine Bemühungen. Ich habe durch Dich dazugelernt und sehe wieder ein kleines Bisschen klarer.

              Liebe Grüße,

              Felix Riesterer.

              --
              ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
            2. moin,

              Ansonsten bleibt dem DBMS nicht viel mehr übrig als das kartesische Produkt der beteiligten Tabellen durchzuarbeiten, d.h. bei k Schülern, l Klassenlisten und m Klassen müssen k*l*n-Kombinationen durchgetestet werden.

              das will ich nicht hoffen. wenn keine sortierung vorliegt, kann das dbms on the fly eines bilden.

              Ilja

      2. Hi,

        Indizes auf den Verknüpfungsspalten.

        das war eben zu kurz, um mir weiterzuhelfen.

        Inwiefern sind denn meine ON-Statements keine "Verknüpfungsspalten"? Und inwiefern sind es keine Indices?

        Die in den ON-Bedingungen vorkommenden Spalten sind Verknüpfungsspalten - denn sie dienen ja dazu, die Tabellen zu verknüpfen (zu "joinen").

        Ob auf diesen Spalten Indezes liegen, kann ich nicht beurteilen, da Du ja keine Angaben zum Datenmodell machst.

        cu,
        Andreas

        --
        Warum nennt sich Andreas hier MudGuard?
        O o ostern ...
        Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
        1. Lieber MudGuard,

          Die in den ON-Bedingungen vorkommenden Spalten sind Verknüpfungsspalten - denn sie dienen ja dazu, die Tabellen zu verknüpfen (zu "joinen").

          OK, bis hierher kann ich Dir folgen.

          Ob auf diesen Spalten Indezes liegen, kann ich nicht beurteilen, da Du ja keine Angaben zum Datenmodell machst.

          Stimmt. Das wäre momentan auch ziemlich umfangreich. Das wollte ich zunächst vermeiden. Zur Lösungsfindung habe ich aber die notwendigen Stichworte erhalten (sowohl von Dir, als auch von Vinzenz). Danke!

          Liebe Grüße,

          Felix Riesterer.

          --
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  2. Hi,

    Ohne Joins geht eine Abfrage recht schnell (gefühlte halbe Sekunde),

    sagtest Du eine _halbe Sekunde_?! Wow, das ist das Äquivalent eines Bobby Cars auf der Autobahn. Ich hoffe doch sehr, Du selektierst viele tausend Datensätze, und die Zeit ist einschließlich ihrer Verarbeitung und Ausgabe. Ansonsten ist das nämlich Preisträger des Slowest Query Awards ...

    Wer weiß Rat, wie ich das optimieren kann?

    Höchstwahrscheinlich genau so wie die Joins ;-)

    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. Lieber Cheatah,

      Ohne Joins geht eine Abfrage recht schnell (gefühlte halbe Sekunde),

      sagtest Du eine _halbe Sekunde_?!

      nein, ich sagte eine "gefühlte" halbe Sekunde. Das ist die Zeit, bis mein Dokument im Browser nach dem Aufruf geladen hat. Und da merkte ich einen sehr spürbaren Zeitunterschied mit bzw. ohne Join.

      Mir ist klar, dass die tatsächliche Abfrage im DBMS im Millisekundenbereich liegt, insbesondere bei ca. 5000 Datensätzen...

      Wow, das ist das Äquivalent eines Bobby Cars auf der Autobahn.

      Alleine das Bild sich vorzustellen hat etwas besonders Ostern-haftes[1]! LOL!

      Ich hoffe doch sehr, Du selektierst viele tausend Datensätze, und die Zeit ist einschließlich ihrer Verarbeitung und Ausgabe. Ansonsten ist das nämlich Preisträger des Slowest Query Awards ...

      Yep. Siehe oben.

      Fröhliches Eiersuchen!

      Liebe Grüße,

      Felix Riesterer.

      [1] Ostern = Gelegenheit die Verwandtschaft zu sehen
                 = Gemütlichkeit fernab der Alltagshektik
                <= Verkehrsstress mit Bobbycar auf der Autobahn

      --
      ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
      1. Hi,

        sagtest Du eine _halbe Sekunde_?!
        nein, ich sagte eine "gefühlte" halbe Sekunde. Das ist die Zeit, bis mein Dokument im Browser nach dem Aufruf geladen hat.

        hm, Du solltest das ggf. näher untersuchen. Mal von MySQL ausgehend: Ergänze das Statement um "EXPLAIN" und untersuche dessen Ausgabe. Hierzu eignet sich PhpMyAdmin recht gut.

        Mir ist klar, dass die tatsächliche Abfrage im DBMS im Millisekundenbereich liegt, insbesondere bei ca. 5000 Datensätzen...

        So sollte es sein, in der Tat.

        Fröhliches Eiersuchen!

        Hab sie gefunden: Sie waren unter der Stoßstange.

        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. Hi,

          Hab sie gefunden: Sie waren unter der Stoßstange.

          Dann war das aber ein getuntes Bobbycar ;-)

          Gruesse, Joachim

          --
          Am Ende wird alles gut.
  3. Liebe Mitlesende,

    der zielführende Hinweis war die Sache mit den Indices. Seit ich in allen Tabellen die entsprechenden Spalten mit Indices ausgerüstet habe (die Spalten enthielten IDs, die jeweils tabellenübergreifend korellieren), geschieht der Seitenaufbau in einem Bruchteil der Zeit. Inwieweit die Bearbeitungsdauer der Abfrage selbst kürzer geworden ist, habe ich nicht gemessen, aber der spürbare Zeitgewinn ist mir schon genug.

    Herzlichen Dank an alle, die mir so hilfsbereit mit Erklärungen und Hinweisen geantwortet haben!

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)