105 Stimmen

Wann sollte STRAIGHT_JOIN mit MySQL verwendet werden?

Ich hatte gerade eine ziemlich komplexe Abfrage, mit der ich arbeitete, und die 8 Sekunden zur Ausführung benötigte. EXPLAIN zeigte eine seltsame Tabellenreihenfolge an und meine Indizes wurden nicht alle verwendet, selbst mit dem FORCE INDEX-Hinweis. Ich stieß auf das Join-Schlüsselwort STRAIGHT_JOIN und begann, einige meiner INNER JOIN-Schlüsselwörter durch dieses zu ersetzen. Ich konnte eine erhebliche Geschwindigkeitsverbesserung feststellen. Schließlich ersetzte ich für diese Abfrage alle INNER JOIN-Schlüsselwörter durch STRAIGHT_JOIN und die Abfrage läuft jetzt in 0,01 Sekunden.

Meine Frage ist, wann Sie STRAIGHT_JOIN und wann Sie INNER JOIN verwenden? Gibt es einen Grund, STRAIGHT_JOIN nicht zu verwenden, wenn Sie gute Abfragen schreiben?

76voto

nathan Punkte 4493

Ich würde nicht empfehlen, STRAIGHT_JOIN ohne triftigen Grund zu verwenden. Meiner Erfahrung nach wählt der MySQL-Abfrageoptimierer häufiger einen schlechten Abfrageplan aus, als mir lieb ist, aber nicht so oft, dass Sie ihn generell umgehen sollten, was Sie tun würden, wenn Sie immer STRAIGHT_JOIN verwenden.

Meine Empfehlung ist, alle Abfragen als reguläre JOINs zu belassen. Wenn Sie feststellen, dass eine Abfrage einen suboptimalen Abfrageplan verwendet, würde ich vorschlagen, zunächst zu versuchen, die Abfrage ein wenig umzuschreiben oder umzustrukturieren, um zu sehen, ob der Optimierer dann einen besseren Abfrageplan auswählt. Vergewissern Sie sich außerdem, zumindest bei innodb, dass nicht nur Ihre Indexstatistiken veraltet sind ( TABELLE ANALYSIEREN ). Dies kann dazu führen, dass der Optimierer einen schlechten Abfrageplan auswählt. Optimierungshinweise sollten in der Regel der letzte Ausweg sein.

Ein weiterer Grund, keine Query Hints zu verwenden, ist die Tatsache, dass sich Ihre Datenverteilung im Laufe der Zeit ändern kann, oder dass sich Ihre Indexselektivität ändert, usw., wenn Ihre Tabelle wächst. Ihre Abfragehinweise, die jetzt optimal sind, können im Laufe der Zeit suboptimal werden. Der Optimierer wird jedoch nicht in der Lage sein, den Abfrageplan aufgrund Ihrer nun veralteten Hinweise anzupassen. Sie bleiben flexibler, wenn Sie dem Optimierer erlauben, die Entscheidungen zu treffen.

34voto

Barry Kelly Punkte 40566

Folgendes Szenario hat sich erst kürzlich bei der Arbeit ergeben.

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 haben eine Abfrage, die wie folgt aussieht:

select a.id, c.id
from a
join b on b.a_id = a.id
join c on c.id = b.c_id

Meiner Erfahrung nach kann MySQL in diesem Fall den Weg C -> B -> A wählen. C ist kleiner als A und B ist riesig, und sie sind alle equijoins.

Das Problem ist, dass MySQL nicht unbedingt die Größe der Schnittmenge zwischen (C.id und B.c_id) und (A.id und B.a_id) berücksichtigt. Wenn die Verknüpfung zwischen B und C genau so viele Zeilen wie B zurückgibt, dann ist es eine sehr schlechte Wahl; wenn das Beginnen mit A B auf so viele Zeilen wie A heruntergefiltert hätte, dann wäre es eine viel bessere Wahl gewesen. straight_join könnte verwendet werden, um diese Reihenfolge wie folgt zu erzwingen:

select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id

Jetzt a muss vor dem Einschalten von b .

Im Allgemeinen möchten Sie Ihre Joins in einer Reihenfolge durchführen, die die Anzahl der Zeilen in der Ergebnismenge minimiert. Es ist also ideal, mit einer kleinen Tabelle zu beginnen und die Verknüpfung so durchzuführen, dass die resultierende Verknüpfung ebenfalls klein ist. Wenn Sie mit einer kleinen Tabelle beginnen und diese mit einer größeren Tabelle verbinden, wird die resultierende Menge genauso groß wie die große Tabelle.

Das ist allerdings statistikabhängig. Wenn sich die Datenverteilung ändert, kann sich auch die Berechnung ändern. Sie hängt auch von den Implementierungsdetails des Verknüpfungsmechanismus ab.

Die schlimmsten Fälle, die ich für MySQL gesehen habe, die alles andere als erforderlich waren straight_join oder aggressives Index Hinting sind Abfragen, die über eine Menge von Daten in einer strengen Sortierreihenfolge mit leichter Filterung paginieren. Das macht Sinn, weil die meisten Leute nicht versuchen, die gesamte Datenbank zu sortieren, sondern eher eine begrenzte Teilmenge von Zeilen haben, die auf die Anfrage reagieren, und das Sortieren einer begrenzten Teilmenge viel schneller ist als das Filtern der gesamten Tabelle, egal ob sie sortiert ist oder nicht. In diesem Fall hat die direkte Verknüpfung unmittelbar nach der Tabelle mit der indizierten Spalte, nach der ich sortieren wollte, Abhilfe geschaffen.

25voto

jjclarkson Punkte 5764

Von MySQL JOIN-Referenz :

"STRAIGHT_JOIN ist ähnlich wie JOIN, nur 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."

19voto

IAdapter Punkte 58848

MySQL ist nicht unbedingt gut darin, die Join-Reihenfolge in komplexen Abfragen zu wählen. Wenn Sie eine komplexe Abfrage als straight_join angeben, führt die Abfrage die Joins in der Reihenfolge aus, in der sie angegeben sind. Indem Sie die Tabelle, die der kleinste gemeinsame Nenner sein soll, an die erste Stelle setzen und straight_join angeben, können Sie die Leistung der Abfrage verbessern.

12voto

Mitendra Punkte 1270

STRAIGHT_JOIN Mit dieser Klausel können Sie die JOIN Reihenfolge: welche Tabelle wird in der äußeren Schleife und welche in der inneren Schleife durchsucht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X