Heim >System-Tutorial >LINUX >Denken Sie daran, in der Unterabfrage auf die „Grube' von MySQL zu treten

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

WBOY
WBOYnach vorne
2024-02-13 18:12:27828Durchsuche
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);

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);

Aber Fakt ist:

mysql> select count(*) from userinfo;

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

mysql> select count(*) from article;

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

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

记踩到 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);

记踩到 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;

记踩到 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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:linuxprobe.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen