Ich habe gerade einen Teil eines Optimierungsartikels gelesen und bin bei der folgenden Aussage fehlerhaft vorgegangen :
Bei Verwendung von SQL ersetzen Sie Anweisungen
OR
mitUNION
:
select username from users where company = ‘bbc’ or company = ‘itv’;
zu:
select username from users where company = ‘bbc’ union select username from users where company = ‘itv’;
Von einem schnellen EXPLAIN
:
Verwenden von OR
:
Verwenden von UNION
:
Bedeutet das nicht, dass UNION
sich die Arbeit verdoppelt ?
Während ich schätzen UNION
für bestimmte RDBMSes und bestimmte Tabellenschemata können mehr performant, ist dies nicht kategorisch wahr wie der Autor Vorschläge.
Frage
Liege ich falsch?
mysql
sql
performance
union
Jason McCreary
quelle
quelle
UNION
dies mehr Arbeit bedeutet, da die Duplikate entfernt werden müssen, wobei der Filter die angegebenen Kriterien abrufen würde. Ich bin überrascht, dass die Verwendung nicht empfohlen wirdIN
.OR
inWHERE
Klausel.Antworten:
Entweder hat der Artikel, den Sie gelesen haben, ein schlechtes Beispiel verwendet, oder Sie haben ihren Punkt falsch interpretiert.
select username from users where company = 'bbc' or company = 'itv';
Dies entspricht:
select username from users where company IN ('bbc', 'itv');
MySQL kann
company
für diese Abfrage einen Index verwenden . Es ist nicht nötig, eine UNION zu machen.Der schwierigere Fall ist, wenn Sie eine
OR
Bedingung haben, die zwei verschiedene Spalten umfasst.select username from users where company = 'bbc' or city = 'London';
Angenommen, es gibt einen Index
company
und einen separaten Indexcity
. Welchen Index sollte MySQL normalerweise verwenden, da es in einer bestimmten Abfrage normalerweise nur einen Index pro Tabelle verwendet? Wenn der Index aktiviert istcompany
, muss immer noch ein Tabellenscan durchgeführt werden, um Zeilen zu finden, in denencity
sich London befindet. Wenn der Index aktiviert istcity
, müsste ein Tabellenscan nach Zeilen durchgeführt werden, in denencompany
bbc steht.Die
UNION
Lösung ist für diese Art von Fall.select username from users where company = 'bbc' union select username from users where city = 'London';
Jetzt kann jede Unterabfrage den Index für ihre Suche verwenden, und die Ergebnisse der Unterabfrage werden durch die kombiniert
UNION
.Ein anonymer Benutzer schlug eine Bearbeitung meiner obigen Antwort vor, aber ein Moderator lehnte die Bearbeitung ab. Es sollte ein Kommentar gewesen sein, keine Bearbeitung. Die Behauptung der vorgeschlagenen Bearbeitung lautete, dass UNION die Ergebnismenge sortieren muss, um doppelte Zeilen zu entfernen. Dadurch wird die Abfrage langsamer ausgeführt, und die Indexoptimierung ist daher eine Wäsche.
Meine Antwort ist, dass die Indizes dazu beitragen, die Ergebnismenge auf eine kleine Anzahl von Zeilen zu reduzieren, bevor die UNION stattfindet. UNION eliminiert zwar Duplikate, muss dazu jedoch nur die kleine Ergebnismenge sortieren. Es kann Fälle geben, in denen die WHERE-Klauseln mit einem wesentlichen Teil der Tabelle übereinstimmen und das Sortieren während UNION genauso teuer ist wie das einfache Durchführen des Tabellenscans. Es ist jedoch üblicher, dass die Ergebnismenge durch die indizierten Suchvorgänge reduziert wird, sodass die Sortierung viel kostengünstiger ist als der Tabellenscan.
Der Unterschied hängt von den Daten in der Tabelle und den gesuchten Begriffen ab. Die einzige Möglichkeit, die beste Lösung für eine bestimmte Abfrage zu ermitteln, besteht darin, beide Methoden im MySQL-Abfrageprofiler auszuprobieren und ihre Leistung zu vergleichen.
quelle
UNION
vs.OR
war nicht kategorisch wahr . Aber ich markiere dies als richtig, da es das ursprüngliche Beispiel als falsch ansprach und gleichzeitig einen Anwendungsfall dessen lieferte, was der Autor wahrscheinlich meinte .IN()
Prädikate nicht optimiert hat .Das sind nicht die gleichen Abfragen.
Ich habe nicht viel Erfahrung mit MySQL, daher bin ich mir nicht sicher, was der Abfrageoptimierer tut oder nicht, aber hier sind meine Gedanken aus meinem allgemeinen Hintergrund (hauptsächlich MS SQL Server).
In der Regel kann der Abfrageanalysator die beiden oben genannten Abfragen übernehmen und aus ihnen genau den gleichen Plan erstellen (wenn sie gleich wären), sodass dies keine Rolle spielt. Ich würde vermuten, dass es keinen Leistungsunterschied zwischen diesen Abfragen gibt (die gleichwertig sind).
select distinct username from users where company = ‘bbc’ or company = ‘itv’;
und
select username from users where company = ‘bbc’ union select username from users where company = ‘itv’;
Die Frage ist nun, ob es einen Unterschied zwischen den folgenden Abfragen gibt, von denen ich eigentlich nichts weiß, aber ich würde vermuten, dass der Optimierer es eher wie die erste Abfrage machen würde
select username from users where company = ‘bbc’ or company = ‘itv’;
und
select username from users where company = ‘bbc’ union all select username from users where company = ‘itv’;
quelle
UNION ALL
ergibt sich immer noch das gleicheEXPLAIN
wieUNION
.UNION ALL
ist normalerweise schneller alsUNION
. Letzteres impliziertUNION DISTINCT
, wodurch ein De-Dup-Durchlauf über eine temporäre Tabelle erforderlich ist. Neuere Versionen vermeiden in bestimmten Situationen die temporäre Tabelle und helfen so mehr. Dasor
Beispiel, das Sie haben, ist immer schneller, weil es verwenden kannINDEX(company)
Dies hängt davon ab, was der Optimierer letztendlich tut, basierend auf der Größe der Daten, Indizes, Softwareversion usw.
Ich würde vermuten, dass die Verwendung von OR dem Optimierer eine bessere Chance gibt, einige Effizienzvorteile zu erzielen, da alles in einer einzigen logischen Anweisung enthalten ist.
Außerdem hat UNION einen gewissen Overhead, da ein Reset- Set erstellt wird (keine Duplikate). Jede Anweisung in der UNION sollte ziemlich schnell ausgeführt werden, wenn das Unternehmen indiziert ist ... nicht sicher, ob es wirklich die doppelte Arbeit leisten würde.
Endeffekt
Wenn Sie nicht wirklich das brennende Bedürfnis haben, jede Geschwindigkeit aus Ihrer Abfrage herauszuholen, ist es wahrscheinlich besser, einfach das Formular zu verwenden, das Ihre Absicht am besten kommuniziert ... den OP
Aktualisieren
Ich wollte auch IN erwähnen. Ich glaube, dass die folgende Abfrage eine bessere Leistung als der OP liefert (es ist auch die Form, die ich bevorzuge):
select username from users where company in ('bbc', 'itv');
quelle
In fast allen Fällen führt die Version
union
oderunion all
zwei vollständige Tabellenscans der Benutzertabelle durch.Die
or
Version ist in der Praxis viel besser, da die Tabelle nur einmal gescannt wird. Es wird auch nur einmal ein Index verwendet, falls verfügbar.Die ursprüngliche Aussage scheint einfach falsch zu sein, für nahezu jede Datenbank und jede Situation.
quelle
UNION
wird auch ein Index verwendet, falls verfügbar. Es werden jedoch beide Tabellen gescannt . Nur ein kleinerer Datensatz führt sie dann wieder zusammen.or
/ verwenden, werdenin
Sie "Indexbereichsscan" verwenden, und im Fall vonunion
/ werdenunion all
Sienon-unique
oder sogarprimary key lookup
plus verwendenindex merge
IN
undOR
sind die gleichen. Sie können dies sehen, indem SieEXPLAIN
sehen, dass der Optimierer einen in den anderen verwandelt.Die Antwort von Bill Karwin ist ziemlich richtig. Wenn beide Teile der OR-Anweisung einen eigenen Index haben, ist es besser, Union zu machen, da es einfacher ist, sie zu sortieren und Duplikate zu entfernen, wenn Sie nur eine kleine Teilmenge der Ergebnisse haben. Die Gesamtkosten sind fast geringer als die Verwendung nur eines Index (für eine der Spalten) und des Tabellenscans für die andere Spalte (da MySQL nur einen Index für eine Spalte verwendet).
Es hängt von der Struktur und den Bedürfnissen der Tabelle im Allgemeinen ab, aber bei großen Tabellen hat mir die Vereinigung bessere Ergebnisse gebracht.
quelle
mysql only uses one index for one column
- es ist nicht wahr. Sie können Ihre Spalte in vielen Indizes haben.SELECT
". (Dies vermeidet die Mehrdeutigkeit, ob aUNION
eine oder mehrere "Abfragen" ist.)