Warum wäre SELECT * um Größenordnungen schneller als SELECT foo?

28

Betrachten Sie eine Tabelle mit Werten und Hashes wie folgt:

+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| val        | char(9)  | NO   |     | NULL    |                |
| val_hashed | char(50) | YES  |     | NULL    |                |
+------------+----------+------+-----+---------+----------------+

Die folgende Abfrage wird in 0,00 Sekunden beendet:

SELECT * FROM hashes ORDER BY 1 DESC LIMIT 1;

Diese Abfrage dauert jedoch 3 Minuten und 17 Sekunden:

SELECT val FROM hashes ORDER BY 1 DESC LIMIT 1;

Ich sehe, dass die Prozessliste den Status anzeigt, während die Abfrage ausgeführt wird Sorting result. Die Situation ist vollständig reproduzierbar. Beachten Sie, dass ein anderer Prozess INSERTkontinuierlich Vorgänge in der Tabelle ausführt .

Warum würde die Ausführung der spezifischeren Abfrage länger dauern als die *Abfrage? Ich war immer der Meinung, dass *Abfragen aus Performancegründen vermieden werden sollten.

dotancohen
quelle
7
Bei den ersten Anweisungen wird höchstwahrscheinlich der Primärschlüsselindex verwendet id, um die erste Zeile zu finden. Der zweite muss das komplette Ergebnis in der (nicht indizierten) valSpalte sortieren .
a_horse_with_no_name
8
Die ORDER BY NUMBERSyntax ist sehr fehleranfällig.
USR
2
Das Hinzufügen zu Ihrem letzten Kommentar in SELECT *Kombination mit einem Spaltenindex in ORDER BYverschleiert, welche Spalte sortiert wird - ein weiterer Grund, *s ...
lc
Was meinst du?
Pacerier
@Pacerier Ich meine das *ist nicht explizit. Das Sprichwort "Gib mir alle Spalten und sortiere nach der dritten" ist ungefähr so ​​deterministisch wie das Sprichwort "Geh in den Supermarkt und sag mir, wie viele Ampeln du passiert hast"
lc.

Antworten:

33

Die Phrase ORDER BY 1bezieht sich auf verschiedene Spalten; im ersten wird es sein id, im zweiten val. Da ides sich um den Schlüssel handelt, wird er indiziert, und order bydies ist ein geringfügiger Arbeitsaufwand. Um order by valjedoch jede Zeile abzurufen, muss das System die gesamte Tabelle nach sortieren valund dann nur eine dieser Zeilen auswählen.

Ändern Sie beide Abfragen in order by idund ich denke, Ihre Ausführungszeiten werden fast identisch sein.

Michael Green
quelle
3
Manchmal sind die schwierigsten Fragen die, die uns gerade ins Gesicht starren. Danke, Michael!
Dotancohen
7

Der Leistungsunterschied in Ihrer Abfrage wird von MG gut erklärt. Ich werde folgendes ansprechen:

Ich habe immer geglaubt, dass * Abfragen aus Performancegründen vermieden werden sollten.

select *trägt von sich aus keine besonderen Strafen, es ist problematisch bei Missbrauch. In einer Single-Table-Abfrage funktioniert es einwandfrei. Verbinden Sie nun diese Tabelle mit einer anderen mit 20 Spalten und fügen Sie später Verknüpfungen mit 5 anderen Tabellen mit jeweils vielen Spalten hinzu. JETZT ist es ein Problem. So sind es auch Leute, die breit gefächertes Pflaster lehren, "nie X machen", ohne zu erklären warum.

paul
quelle
3
SELECT *Dies kann selbst bei einer Abfrage mit nur einer Tabelle ein Problem sein. Zum Beispiel SELECT * FROM hashes ORDER BY val;wird wahrscheinlich eine vollständige Tabellensuche und dann eine Sortierung durchgeführt, während SELECT val FROM hashes ORDER BY val;nur eine vollständige Indexsuche und keine Sortierung durchgeführt wird (vorausgesetzt, es existiert ein Index für val). Es tut also nie weh, nur die Ergebnisse auszuwählen, die wir brauchen.
Ypercubeᵀᴹ
Ich nehme an, Sie haben das gesehen? sqlblog.com/blogs/aaron_bertrand/archive/2009/10/10/…
Max Vernon
@ypercube, Tritt das auch auf, wenn unser select(*)nur als Unterauswahl verwendet wird? Wäre MySQL nicht klug genug, um die tatsächlichen Spalten zu ermitteln, die ausgewählt werden müssen, da es sich um eine eingebettete Auswahl handelt?
Pacerier
@Pacerier mysql optimizer weist je nach verwendeter Version unterschiedliche "Smartness" -Niveaus auf. In gerneal war es in Bezug auf verschachtelte Unterabfragen ziemlich dumm, also war es gut, was immer Sie konnten, um ihm zu helfen.
ypercubeᵀᴹ
@ypercube, Ah, wenn es nur so schlau ist wie pgsql.
Pacerier