Ich erhalte einen "Bereich für jeden Datensatz (Index-Map: 0x1)" in EXPLAIN SELECT überprüft, wenn Sie einen INNER JOIN auf einem PRIMARY-Schlüssel mit 2 Werten (entweder IN oder OR-Konstrukte)
Hier ist die Abfrage:
%Vor%Wenn ich eine Erklärung mache, gibt es mir:
%Vor%Es kann nicht sein ...
Wenn ich das versuche, bekomme ich das gleiche Ergebnis:
%Vor%Aber wenn ich das tue, funktioniert es gut und ich bekomme nur 1 Zeile geparst:
%Vor%Wie ist das möglich? Ich schließe mich einem Primärschlüssel mit denselben Werten an. (Die tatsächliche Abfrage ist "ein bisschen" komplizierter, aber nichts Besonderes, 2 innere Joins und zuletzt ein linker Join)
Es sollte 2 Zeilen sein, Punkt.
Danke für irgendeinen Beitrag dazu (hat etwas recherchiert, aber nichts Wertvolles gefunden außer "bitte fügen Sie einen Index hinzu", was hier offensichtlich nicht anwendbar ist)
EDIT: Ja, ich habe versucht, die USE INDEX-Anweisung, aber immer noch kein Glück
EDIT: Hier ist ein sehr einfaches Schema, um dieses seltsame Verhalten von MySQL zu reproduzieren:
%Vor%Im Allgemeinen kann MySQL nur einen Index pro Tabellenreferenz in einer Abfrage verwenden (es gibt eine index-merge Algorithmus, aber das funktioniert nicht so oft, wie Sie vielleicht denken).
Ihre Join-Bedingung hat ein OR
zwischen zwei Vergleichen mit indizierten Spalten, und das Optimierungsprogramm kann nicht auswählen, welches das bessere ist, bevor die Daten in der Tabelle Zeile für Zeile geprüft werden.
Eine häufige Problemumgehung besteht darin, anstelle von UNION
eine OR
zwischen einfacheren Abfragen zu erstellen.
Dies verwendet richtige Index-Lookups in beiden Unterabfragen, aber es muss eine temporäre Tabelle verwenden, um das UNION
danach zu beenden. Letztendlich könnte es eine Waschleistung sein. Hängt davon ab, wie viele Datenzeilen untersucht werden müssen und wie viele Zeilen als Ergebnis erzeugt werden.
Das Problem ist auch in anderen (ich denke alle) RDBMS gut bekannt, der Optimierer wird nur eine Regel für jeden Join verwenden.
Wenn die Join-Bedingung komplex ist oder wenn sie ein bekanntes Muster nicht erkennen kann, wird keine Optimierung angewendet und sie wird für den vollständigen Tabellenscan verwendet.
In Ihrem Fall scheint die Bedingung OR
im Hauptjoin einfach zu sein, ist es aber nicht, weil Sie jede Benutzer-ID mit zwei verschiedenen Spalten (nicht konstanten Werten) gleichzeitig überprüfen möchten.
Um es zu lösen, müssen Sie Ihre Join-Bedingung in mehr Unterabfragen aufteilen, damit der Optimierer die bessere Regel für jede verwenden kann.
@ Bill Karwin hat die gemeinsame Lösung vorgeschlagen und es hilft gut, das Problem zu verstehen.
Ein (etwas) besserer Weg, um dieses Problem zu lösen, ist, die Vereinigung um eine Ebene nach oben zu verschieben und der abgeleiteten Tabelle beizutreten:
%Vor% Es wird nicht TEMPORARY
-Tabellen verwendet und es wird nur eine vollständige Tabelle auf test_users
statt auf zwei