Maison  >  Article  >  Tutoriel système  >  N'oubliez pas de marcher sur le "puits" de MySQL dans la sous-requête

N'oubliez pas de marcher sur le "puits" de MySQL dans la sous-requête

WBOY
WBOYavant
2024-02-13 18:12:27771parcourir
Avant-propos

MySQL est une base de données couramment utilisée dans les projets, et dans les requêtes est également très couramment utilisée. Lors du récent débogage du projet, j'ai rencontré une requête de sélection inattendue, qui a en fait pris 33 secondes !

1. Structure du tableau

1. tableau d'informations utilisateur

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

2. tableau des articles

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

select*fromuserinfowhereidin(selectauthor_idfromartilcewheretype=1);

Lorsque vous voyez pour la première fois le SQL ci-dessus, vous pensez peut-être qu'il s'agit d'une sous-requête très simple. Recherchez d’abord le author_id, puis utilisez-le pour l’interroger.

S'il existe un index pertinent, ce sera très rapide En terme de démontage, il est le suivant :

1.selectauthor_idfromartilcewheretype=1;  2.select*fromuserinfowhereidin(1,2,3);

Mais le fait est le suivant :

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 secondes ! Pourquoi est-ce si lent ?

3. Cause du problème

Explication du document officiel : La clause in est parfois convertie en exist lors de l'interrogation, et est parcourue enregistrement par enregistrement (existant en version 5.5, optimisé en 5.6).

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

Référence :

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

4.Solution (version 5.5)

1. Utiliser une table temporaire

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. Utilisez rejoindre

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

where a.id = b.author_id and b.type = 1;

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

5. Supplément

La version 5.6 a été optimisée pour les sous-requêtes. La méthode est la même que la méthode des tables temporaires dans [4].

Si la matérialisation n'est pas utilisée, l'optimiseur réécrit parfois une sous-requête non corrélée en sous-requête corrélée.

Par exemple, la sous-requête IN suivante n'est pas corrélée (where_condition implique uniquement les colonnes de t2 et non de t1) :

sélectionner * à partir de t1

where t1.a in (sélectionnez t2.b à partir de t2wherewhere_condition);

L'optimiseur

pourrait réécrire ceci sous la forme d'une sous-requête corrélée EXISTS :

sélectionner * à partir de t1

where existe (sélectionnez t2.b à partir de t2 oùwhere_condition et t1.a=t2.b);

Matérialisation de sous-requête

l'utilisation d'une table temporaire évite de telles réécritures et permet d'exécuter la sous-requête une seule fois plutôt qu'une fois par ligne de la requête externe.

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

L'article provient du compte public WeChat : entretiens techniques de première ligne avec HULK

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer