Mysql Join Performance Frage
Daniel Petratsch
- datenbank
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
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
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
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