2016-07-07 7 views
2

Was für SELECT * FROM Table VS die Leistungseinbuße ist SELECT * FROM (SELECT * FROM Table AS A) AS BLeistungseinbuße für verschachtelte MySQL-Abfragen

Meine Fragen sind: Zum einen ist die SELECT * beinhalten Iteration über die Zeilen in der Tabelle, oder wird es einfach zurückgeben alle Zeilen als Chunk ohne Iteration (weil keine WHERE-Klausel angegeben wurde), und wenn ja, involviert die geschachtelte Abfrage in Beispiel zwei das wiederholte Durchlaufen der Tabelle zweimal und benötigt zweimal die Zeit der ersten Abfrage? Danke ...

Antwort

2

Die Antwort auf diese Frage hängt davon ab, ob Sie MySQL vor 5.7 oder 5.7 und danach verwenden. Ich kann Ihre Frage leicht ändern, aber hoffentlich fängt das folgende ein, wonach Sie suchen.

Ihr SELECT * FROM Table führt einen Tabellenscan über den gruppierten Index durch (die physische Reihenfolge). Wenn kein Primärschlüssel vorhanden ist, ist implicitly für den Motor verfügbar. Es gibt keine Where-Klausel, wie Sie sagen. Es wird keine Filterung oder Auswahl eines anderen Indexes versucht.

Der Explain Ausgang (siehe also) zeigt 1 Reihe in seiner Zusammenfassung. Es ist relativ geradlinig. Die EXPLAIN-Ausgabe und die Leistung mit Ihrer abgeleiteten Tabelle B unterscheiden sich je nachdem, ob Sie eine Version vor 5.7, oder 5.7 und danach haben.

Das Dokument Derived Tables in MySQL 5.7 beschreibt es gut für die Versionen 5.6 und 5.7, wobei letzteres keine Nachteile aufgrund der Änderung in der materialisierten abgeleiteten Tabellenausgabe, die in die äußere Abfrage aufgenommen wird, vorsieht. In früheren Versionen wurde erheblicher Overhead mit temporären Tabellen mit dem abgeleiteten System ertragen.

Es ist ziemlich einfach, die Leistungseinbußen vor 5.7 zu testen. Sie benötigen lediglich eine mittelgroße Tabelle, um die spürbaren Auswirkungen der abgeleiteten Tabelle Ihrer Frage auf die Leistung zu erkennen. Das folgende Beispiel ist auf einem kleinen Tisch in der Version 5.6:

explain 
select qm1.title 
from questions_mysql qm1 
join questions_mysql qm2 
on qm2.qid<qm1.qid 
where qm1.qid>3333 and qm1.status='O'; 
+----+-------------+-------+-------+-----------------+---------+---------+------+-------+------------------------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra           | 
+----+-------------+-------+-------+-----------------+---------+---------+------+-------+------------------------------------------------+ 
| 1 | SIMPLE  | qm1 | range | PRIMARY,cactus1 | PRIMARY | 4  | NULL | 5441 | Using where         | 
| 1 | SIMPLE  | qm2 | ALL | PRIMARY,cactus1 | NULL | NULL | NULL | 10882 | Range checked for each record (index map: 0x3) | 
+----+-------------+-------+-------+-----------------+---------+---------+------+-------+------------------------------------------------+ 


explain 
select b.title from 
( select qid,title from questions_mysql where qid>3333 and status='O' 
) b 
join questions_mysql qm2 
on qm2.qid<b.qid; 
+----+-------------+-----------------+-------+-----------------+---------+---------+------+-------+----------------------------------------------------+ 
| id | select_type | table   | type | possible_keys | key  | key_len | ref | rows | Extra            | 
+----+-------------+-----------------+-------+-----------------+---------+---------+------+-------+----------------------------------------------------+ 
| 1 | PRIMARY  | qm2    | index | PRIMARY,cactus1 | cactus1 | 10  | NULL | 10882 | Using index          | 
| 1 | PRIMARY  | <derived2>  | ALL | NULL   | NULL | NULL | NULL | 5441 | Using where; Using join buffer (Block Nested Loop) | 
| 2 | DERIVED  | questions_mysql | range | PRIMARY,cactus1 | PRIMARY | 4  | NULL | 5441 | Using where          | 
+----+-------------+-----------------+-------+-----------------+---------+---------+------+-------+----------------------------------------------------+ 

Hinweis, ich habe die Frage ändern, aber es zeigt die Auswirkungen, die Tabellen und deren fehlende Index Verwendung abgeleitet mit der Optimierer in Versionen hat vor 5.7 . Die abgeleitete Tabelle profitiert von Indizes, wenn sie materialisiert werden. Danach hält es jedoch den Aufwand als temporäre Tabelle aufrecht und wird ohne Verwendung des Index in die äußere Abfrage integriert. Dies ist nicht der Fall in Version 5.7

+0

Große Erklärung :) –

+0

Zum Thema der Leistung, in einer Join-Operation zwischen zwei Unterabfragen, ist es bevorzugt, die Klausel LIMIT in einer inneren Abfrage und nicht auf der äußeren Abfrage angeben? wie: '((SELECT ID FROM Table1 LIMIT 10) Als NATÜRLICHER JOIN Table2))' wäre besser als '((SELECT id FROM Table1) ALS NATÜRLICHER JOIN Table2)) LIMIT 10' (das könnte Syntaxfehler enthalten in Beziehung zu Tabellenbenennung aber ...)? Danke :) –

+0

Am besten mit ihm auf Ihrer Server-Version, Ihr Schema zu spielen. Das folgende ist auf [5.6] (http://i.imgur.com/jxsrvB2.jpg), auf einem Laptop nicht-Server-Klasse. Hinweis: Ich verwende niemals natürliche Joins. Ich versuche, keine breiten Pinselstrich-Antworten zu geben. Vor allem nur auf "Explain" Ausgabe, die identisch erscheinen mag. Das passiert zu viel auf dem Stapel. Stattdessen sollten Sie unsere Abfragen auf größere Datasets ausrichten und mindestens 15 Minuten lang Tests zu unseren am schlechtesten ablaufenden Abfragen oder allgemeinen Untersuchungen wie [hier] (http://stackoverflow.com/a/38189113) durchführen. Die Leistung variiert je nach Version basierend auf dem Optimierer. – Drew

Verwandte Themen