Daniel Petratsch: Mysql Join Performance Frage

Hallo!

Ich habe eine Frage zwecks der Performance von Mysql Join Abfragen:

Angenommen ich habe eine Tabelle mit Artikel und eine Tabelle mit zugehörigen Lieferanten, die am Lieferantenordersatz gejoined werden, so würde die Otto-NormalMysqlBenutzerabfrage in etwa so aussehen:

------->
SELECT   a.ordersatz,a.ueberschrift,a.beschreibung,a.verkaufspreis,a.gewicht,a.laenge,a.breite,a.hoehe,a.lieferzeit,
b.firmenname,b.plz,b.ort,b.lieferzeit
FROM artikel AS a
INNER JOIN lieferantendaten as b
ON (a.ordersatz = b.ordersatz)
WHERE a.artikel_nr = "10025";
------->

Aber nun ist es ja so, dass zuerst die ganzen Daten in einer Temporären Tabelle gejoined werden, und dann erst durch die WHERE Klausel die entsprechenden Tupel selektiert werden. Das heisst also konkret, wenn ich angenommen 50.000 Artikel habe, so werden zuerst alle 50.000 Datensätze mit dem entsprechenden Lieferanten gejoined und danach wird genau 1 Artikel aus den 50.000 herausselektiert. Also sind das dann ja 49.999 umsonst gejointe Datensätze...

Mein meiner Meinung nach besserer Ansatz wäre dieser:

------->
SELECT  a.ordersatz,a.ueberschrift,a.beschreibung,a.verkaufspreis,a.gewicht,a.laenge,a.breite,a.hoehe,a.lieferzeit,
b.firmenname,b.plz,b.ort,b.lieferzeit
FROM artikel AS a
INNER JOIN lieferantendaten as b
ON (a.ordersatz = b.ordersatz AND a.artikel_nr = "10025")
WHERE a.artikel_nr = "10025";
------->

So wird ja eigentlich von Anfang an nur der benötigte Datensatz gejoined, temporär abgelegt und danach wird dieser mittels der WHERE Klausel herausselektiert. Ich habe einmal im Mysql Online Manual irgendwo gelesen, dass man solche Bedingung aber nicht in der Join Klausel setzen sollte, also meine Frage, ist dieses Statement gerechtfertigt, oder kann es da irgendwie zu Komplikationen kommen, weil es ja explizit nicht gemacht werden sollte? Es wäre halt von der Performance her schon um einiges besser denke ich mal.

freundliche Grüsse,
Daniel

--
Das ist der ganze Jammer, die Dummen sind immer so sicher und die Gescheiten so voller Zweifel.
[Bertrand Russell]
  1. Halihallo Daniel

    Aber nun ist es ja so, dass zuerst die ganzen Daten in einer Temporären Tabelle gejoined werden, und dann erst durch die WHERE Klausel die entsprechenden Tupel selektiert werden. Das heisst also konkret, wenn ich angenommen 50.000 Artikel habe, so werden zuerst alle 50.000 Datensätze mit dem entsprechenden Lieferanten gejoined und danach wird genau 1 Artikel aus den 50.000 herausselektiert. Also sind das dann ja 49.999 umsonst gejointe Datensätze...

    Dem ist mit nichten so. MySQL hat einen Query-Optimizer. Falls dieser
    eine WHERE-Bedingung sieht, die einen ganzen PRIMARY KEY oder UNIQUE
    INDEX umfasst, dann wird zuerst diese Tabelle gelesen und mit den
    anderen gejoint, die anderen werden über die eq_ref Optimierung
    beschleunigt. Die a.artikel_nr=xxx wird über "const" Optimierung
    beschleunigt.

    So wird ja eigentlich von Anfang an nur der benötigte Datensatz gejoined, temporär abgelegt und danach wird dieser mittels der WHERE Klausel herausselektiert. Ich habe einmal im Mysql Online Manual irgendwo gelesen, dass man solche Bedingung aber nicht in der Join Klausel setzen sollte

    Richtig, die JOIN-Bedingung definiert den Join, nicht den zu
    selektierenden Datensatz des Result Sets.

    also meine Frage, ist dieses Statement gerechtfertigt, oder kann es da irgendwie zu Komplikationen kommen, weil es ja explizit nicht gemacht werden sollte? Es wäre halt von der Performance her schon um einiges besser denke ich mal.

    Kommt performancetechnisch IHMO auf genau dasselbe raus, bis auf die
    falsch verwendete JOIN Bedingung.

    Verwende mal http://www.mysql.com/doc/en/EXPLAIN.html, um
    MySQL's Optimierungen zu sehen.

    Lies dir auch die anderen Query-Optimizations - beschrieben in der
    oben genannten Ressource - an.

    Viele Grüsse

    Philipp

    1. Halihallo Daniel

      Dem ist mit nichten so. MySQL hat einen Query-Optimizer. Falls dieser
      eine WHERE-Bedingung sieht, die einen ganzen PRIMARY KEY oder UNIQUE
      INDEX umfasst, dann wird zuerst diese Tabelle gelesen und mit den
      anderen gejoint, die anderen werden über die eq_ref Optimierung
      beschleunigt. Die a.artikel_nr=xxx wird über "const" Optimierung
      beschleunigt.

      Als Konsequenz dieser Optimierungen hat die "temporäre Tabelle"
      _immer genau_ einen Datensatz, genauso wie die Ergebnismenge.
      Zuerst wird eben a.artikel_nr in die "temporäre Tabelle" geschrieben,
      diese hat dann genau einen Datensatz. Diese wird dann mit den anderen
      Tabellen - mit eq_ref - Optimierung - gejoint und hat somit auch dann
      nur genau einen Datensatz.

      Stark, was? :-)

      Viele Grüsse

      Philipp

      1. Hi Philipp

        Als Konsequenz dieser Optimierungen hat die "temporäre Tabelle"
        _immer genau_ einen Datensatz, genauso wie die Ergebnismenge.
        Zuerst wird eben a.artikel_nr in die "temporäre Tabelle" geschrieben,
        diese hat dann genau einen Datensatz. Diese wird dann mit den anderen
        Tabellen - mit eq_ref - Optimierung - gejoint und hat somit auch dann
        nur genau einen Datensatz.

        Stark, was? :-)

        Danke für die Antwort, ja hört sich ganz gut an was du mir da erzählst, das muss dann natürlich gleich mal in die Tat umgesetzt werden :) Ich habe zwar schon gewusst, dass Mysql intern ein weing optimiert, aber nicht was und wie und meistens liest man im Internet nur die starren theoretischen mathematischen
        Ansätze wie diese Operationen eigentlich so funktionieren, und da wird dann anscheinend immer vom Worst Case ausgegangen.

        freundliche Grüsse,
        Daniel

        --
        Das ist der ganze Jammer, die Dummen sind immer so sicher und die Gescheiten so voller Zweifel.
        [Bertrand Russell]