Ich hatte gerade eine ziemlich komplexe Abfrage, mit der ich gearbeitet habe, und die Ausführung dauerte 8 Sekunden. EXPLAIN zeigte eine seltsame Tabellenreihenfolge und meine Indizes wurden nicht alle verwendet, selbst mit dem FORCE INDEX-Hinweis. Ich bin auf das Join-Schlüsselwort STRAIGHT_JOIN gestoßen und habe begonnen, einige meiner INNER JOIN-Schlüsselwörter durch dieses zu ersetzen. Ich bemerkte eine erhebliche Geschwindigkeitsverbesserung. Schließlich habe ich gerade alle meine INNER JOIN-Schlüsselwörter für diese Abfrage durch STRAIGHT_JOIN ersetzt und sie wird jetzt in 0,01 Sekunden ausgeführt.
Meine Frage ist, wann Sie STRAIGHT_JOIN verwenden und wann Sie INNER JOIN verwenden? Gibt es einen Grund, STRAIGHT_JOIN nicht zu verwenden, wenn Sie gute Abfragen schreiben?
straight_join
.Aus der MySQL JOIN-Referenz :
"STRAIGHT_JOIN ähnelt JOIN, außer dass die linke Tabelle immer vor der rechten Tabelle gelesen wird. Dies kann für die (wenigen) Fälle verwendet werden, in denen der Join-Optimierer die Tabellen in die falsche Reihenfolge bringt."
quelle
Hier ist ein Szenario, das erst kürzlich bei der Arbeit aufgetaucht ist.
Betrachten Sie drei Tabellen, A, B, C.
A hat 3.000 Zeilen; B hat 300.000.000 Zeilen; und C hat 2.000 Zeilen.
Fremdschlüssel sind definiert: B (a_id), B (c_id).
Angenommen, Sie hatten eine Abfrage, die folgendermaßen aussieht:
Nach meiner Erfahrung kann MySQL in diesem Fall C -> B -> A wählen. C ist kleiner als A und B ist enorm und sie sind alle gleichwertig.
Das Problem ist, dass MySQL nicht unbedingt die Größe des Schnittpunkts zwischen (C.id und B.c_id) und (A.id und B.a_id) berücksichtigt. Wenn die Verknüpfung zwischen B und C genauso viele Zeilen wie B zurückgibt, ist dies eine sehr schlechte Wahl. Wenn das Beginnen mit A B auf so viele Zeilen wie A heruntergefiltert hätte, wäre es eine viel bessere Wahl gewesen.
straight_join
könnte verwendet werden, um diese Reihenfolge wie folgt zu erzwingen:Jetzt
a
muss vorher noch mitgemacht werdenb
.Im Allgemeinen möchten Sie Ihre Verknüpfungen in einer Reihenfolge ausführen, in der die Anzahl der Zeilen in der resultierenden Menge minimiert wird. Es ist daher ideal, mit einer kleinen Tabelle zu beginnen und so zu verbinden, dass die resultierende Verknüpfung ebenfalls klein ist. Die Dinge werden birnenförmig, wenn man mit einem kleinen Tisch beginnt und ihn mit einem größeren Tisch verbindet, der genauso groß ist wie der große Tisch.
Es ist jedoch abhängig von den Statistiken. Wenn sich die Datenverteilung ändert, kann sich die Berechnung ändern. Dies hängt auch von den Implementierungsdetails des Join-Mechanismus ab.
Die schlimmsten Fälle, die ich für MySQL gesehen habe, die alles andere als erforderlich sind,
straight_join
oder aggressive Indexhinweise, sind Abfragen, die über viele Daten in einer strengen Sortierreihenfolge mit Lichtfilterung paginieren. MySQL bevorzugt nachdrücklich die Verwendung von Indizes für Filter und Verknüpfungen über Sortierungen. Dies ist sinnvoll, da die meisten Benutzer nicht versuchen, die gesamte Datenbank zu sortieren, sondern nur eine begrenzte Teilmenge von Zeilen haben, die auf die Abfrage reagieren. Das Sortieren einer begrenzten Teilmenge ist viel schneller als das Filtern der gesamten Tabelle, unabhängig davon, ob sie sortiert ist oder nicht nicht. In diesem Fall wollte ich die direkte Verknüpfung unmittelbar nach der Tabelle mit der indizierten Spalte setzen, die ich nach festen Dingen sortieren wollte.quelle
straight_join
wertet die linke Tabelle vor der rechten aus. Wenn Sie also vonA -> B -> C
meinem Beispiel ausgehen möchten , könnte das erstejoin
Schlüsselwort durch ersetzt werdenstraight_join
.MySQL ist nicht unbedingt gut darin, die Verknüpfungsreihenfolge in komplexen Abfragen auszuwählen. Durch Angabe einer komplexen Abfrage als Straight_Join führt die Abfrage die Verknüpfungen in der angegebenen Reihenfolge aus. Indem Sie die Tabelle zuerst auf den kleinsten gemeinsamen Nenner setzen und gerade_join angeben, können Sie die Abfrageleistung verbessern.
quelle
STRAIGHT_JOIN
Mit dieser Klausel können Sie dieJOIN
Reihenfolge steuern : Welche Tabelle wird in der äußeren Schleife gescannt und welche in der inneren Schleife.quelle
Ich werde Ihnen sagen, warum ich STRAIGHT_JOIN verwenden musste:
Daher habe ich einen der Joins gezwungen, Straight_Join zu sein, um den vorherigen Join zu erzwingen, der zuerst gelesen werden soll. Dies verhinderte, dass MySQL die Ausführungsreihenfolge änderte, und wirkte wie ein Zauber!
quelle
Nach meiner kurzen Erfahrung ist eine der Situationen,
STRAIGHT_JOIN
die meine Abfrage von 30 Sekunden auf 100 Millisekunden reduziert hat, dass die erste Tabelle im Ausführungsplan nicht die Tabelle war, die die Reihenfolge nach Spalten hatWenn der Optimierer
stores
zuerst trifft , wird dies verursacht,Using index; Using temporary; Using filesort
weilQuelle
Hier braucht der Optimierer ein wenig Hilfe, indem er ihm sagt, er solle
sales
zuerst mit drückenquelle
Wenn Ihre Abfrage mit endet
ORDER BY... LIMIT...
, ist es möglicherweise optimal, die Abfrage neu zu formulieren, um den Optimierer dazu zu bringen, dasLIMIT
vor dem zu tunJOIN
.(Diese Antwort gilt nicht nur für die ursprüngliche Frage zu
STRAIGHT_JOIN
, noch gilt sie für alle Fälle vonSTRAIGHT_JOIN
.)Beginnend mit dem Beispiel von @Accountant م sollte dies in den meisten Situationen schneller laufen. (Und es werden keine Hinweise benötigt.)
Anmerkungen:
INDEX(date, id)
.sales
Sie nur 50 "Whatevers", ohne sie in einer temporären Tabelle herumzuschleppen.ORDER BY
muss sie in der äußeren Abfrage wiederholt werden. (Der Optimierer findet möglicherweise einen Weg, um zu vermeiden, dass tatsächlich eine andere Sortierung durchgeführt wird.)Ich bin gegen die Verwendung von Treffern, weil "Auch wenn es heute schneller ist, kann es morgen nicht schneller sein."
quelle
Ich weiß, dass es ein bisschen alt ist, aber hier ist ein Szenario: Ich habe ein Batch-Skript erstellt, um eine bestimmte Tabelle zu füllen. Irgendwann lief die Abfrage sehr langsam. Es scheint, dass die Verknüpfungsreihenfolge in bestimmten Datensätzen falsch war:
Eine falsche Reihenfolge wird ca. 65 Sekunden lang ausgeführt, während bei Verwendung von Straight_Join in Millisekunden ausgeführt wird
quelle
quelle