Maison > Tutoriel système > Linux > 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
Libérer: 2024-02-13 18:12:27
avant
814 Les gens l'ont consulté
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);
Copier après la connexion

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);
Copier après la connexion

Mais le fait est le suivant :

mysql> select count(*) from userinfo;
Copier après la connexion

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

mysql> select count(*) from article;
Copier après la connexion

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

mysql> select id,username from userinfo where id in (select author_id from article where type = 1);
Copier après la connexion

记踩到 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);
Copier après la connexion

记踩到 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;
Copier après la connexion

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

source:linuxprobe.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal