Heim > System-Tutorial > LINUX > Hauptteil

Denken Sie daran, in der Unterabfrage auf die „Grube' von MySQL zu treten

WBOY
Freigeben: 2024-02-13 18:12:27
nach vorne
797 Leute haben es durchsucht
Vorwort

MySQL ist eine häufig verwendete Datenbank in Projekten und wird auch sehr häufig in Abfragen verwendet. Beim letzten Debuggen des Projekts bin ich auf eine unerwartete Auswahlabfrage gestoßen, die tatsächlich 33 Sekunden dauerte!

1. Tabellenstruktur

1. Benutzerinfotabelle

记踩到 MySQL in 子查询的“坑”

2. Artikeltabelle

记踩到 MySQL in 子查询的“坑”

select*fromuserinfowhereidin(selectauthor_idfromartilcewheretype=1);
Nach dem Login kopieren

Wenn Sie das obige SQL zum ersten Mal sehen, denken Sie vielleicht, dass es sich um eine sehr einfache Unterabfrage handelt. Ermitteln Sie zuerst die Autor_ID und fragen Sie sie dann mit in ab.

Wenn ein relevanter Index vorhanden ist, erfolgt die Demontage wie folgt:

1.selectauthor_idfromartilcewheretype=1;  2.select*fromuserinfowhereidin(1,2,3);
Nach dem Login kopieren

Aber Fakt ist:

mysql> select count(*) from userinfo;
Nach dem Login kopieren

记踩到 MySQL in 子查询的“坑”

mysql> select count(*) from article;
Nach dem Login kopieren

记踩到 MySQL in 子查询的“坑”

mysql> select id,username from userinfo where id in (select author_id from article where type = 1);
Nach dem Login kopieren

记踩到 MySQL in 子查询的“坑”

33 Sekunden! Warum ist es so langsam?

3. Ursache des Problems

Offizielle Dokumenterklärung: Die in-Klausel wird bei Abfragen manchmal in „exists“ konvertiert und Datensatz für Datensatz durchlaufen (vorhanden in Version 5.5, optimiert in 5.6).

记踩到 MySQL in 子查询的“坑”

Referenz:

https://dev.mysql.com/doc/refman/5.5/en/subquery-optimization.html

4. Lösung (Version 5.5)

1. Verwenden Sie eine temporäre Tabelle

select id,username from userinfo

where id in (select author_id from

(select author_id from article where type = 1) as tb);
Nach dem Login kopieren

记踩到 MySQL in 子查询的“坑”

2. Verwenden Sie Join

select a.id,a.username from userinfo a, article b

where a.id = b.author_id and b.type = 1;
Nach dem Login kopieren

记踩到 MySQL in 子查询的“坑”

5. Ergänzung

Version 5.6 wurde für Unterabfragen auf die gleiche Weise optimiert wie die temporäre Tabelle in [4]. Bitte beachten Sie die offizielle Dokumentation:

Wenn keine Materialisierung verwendet wird, schreibt der Optimierer manchmal eine nicht korrelierte Unterabfrage in eine korrelierte Unterabfrage um.

Zum Beispiel ist die folgende IN-Unterabfrage nicht korreliert (wobei_bedingung nur Spalten von t2 und nicht von t1 betrifft):

wählen Sie * aus t1

where t1.a in (wählen Sie t2.b aus t2 where where_condition aus);

Der Optimierer könnte dies als EXISTS-korrelierte Unterabfrage umschreiben:

wählen Sie * aus t1

wo existiert (wählen Sie t2.b aus t2 aus, wobei where_condition und t1.a=t2.b);

Die Materialisierung von Unterabfragen die Verwendung einer temporären Tabelle vermeidet solche Umschreibungen und ermöglicht es, die Unterabfrage nur einmal und nicht einmal pro Zeile der äußeren Abfrage auszuführen.

https://dev.mysql.com/doc/refman/5.6/en/subquery-materialization.html

Der Artikel stammt aus dem öffentlichen WeChat-Konto: HULK technische Gespräche an vorderster Front

Das obige ist der detaillierte Inhalt vonDenken Sie daran, in der Unterabfrage auf die „Grube' von MySQL zu treten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:linuxprobe.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage