Ci-dessous deux requêtes sont des sous-requêtes. Les deux sont les mêmes et les deux fonctionnent bien pour moi. Mais le problème est que la requête de la méthode 1 prend environ 10 secondes à s'exécuter, tandis que celle de la méthode 2 prend moins de 1 s.
J'ai pu convertir la requête de la méthode 1 en méthode 2, mais je ne comprends pas ce qui se passe dans la requête. J'ai essayé de comprendre moi-même. J'aimerais vraiment savoir quelle est la différence entre deux requêtes ci-dessous et comment le gain de performances se produit-il? Quelle est la logique derrière tout ça?
Je suis nouveau dans ces techniques avancées. J'espère que quelqu'un va m'aider ici. Étant donné que je lis les docs qui ne me donne pas la moindre idée.
Méthode 1:
SELECT
*
FROM
tracker
WHERE
reservation_id IN (
SELECT
reservation_id
FROM
tracker
GROUP BY
reservation_id
HAVING
(
method = 1
AND type = 0
AND Count(*) > 1
)
OR (
method = 1
AND type = 1
AND Count(*) > 1
)
OR (
method = 2
AND type = 2
AND Count(*) > 0
)
OR (
method = 3
AND type = 0
AND Count(*) > 0
)
OR (
method = 3
AND type = 1
AND Count(*) > 1
)
OR (
method = 3
AND type = 3
AND Count(*) > 0
)
)
Méthode 2:
SELECT
*
FROM
`tracker` t
WHERE
EXISTS (
SELECT
reservation_id
FROM
`tracker` t3
WHERE
t3.reservation_id = t.reservation_id
GROUP BY
reservation_id
HAVING
(
METHOD = 1
AND TYPE = 0
AND COUNT(*) > 1
)
OR
(
METHOD = 1
AND TYPE = 1
AND COUNT(*) > 1
)
OR
(
METHOD = 2
AND TYPE = 2
AND COUNT(*) > 0
)
OR
(
METHOD = 3
AND TYPE = 0
AND COUNT(*) > 0
)
OR
(
METHOD = 3
AND TYPE = 1
AND COUNT(*) > 1
)
OR
(
METHOD = 3
AND TYPE = 3
AND COUNT(*) > 0
)
)
Un Explain Plan
vous aurait montré pourquoi vous devriez utiliser exactement Exists
. Habituellement, la question vient de Exists vs Count(*)
. Exists
est plus rapide. Pourquoi?
En ce qui concerne les défis présents par NULL: lorsque sous-requête renvoie Null
, pour IN la requête entière devient Null
. Donc, vous devez gérer cela aussi. Mais en utilisant Exist
, c’est simplement un false
. Beaucoup plus facile de faire face. IN
ne peut tout simplement pas comparer avec Null
mais Exists
can.
par exemple. Exists (Select * from yourtable where bla = 'blabla');
vous obtenez true/false au moment où un hit est trouvé/reconnu.
Dans ce cas, IN
sort de la position de Count(*)
pour sélectionner ALL les lignes correspondantes en fonction de WHERE
car toutes les valeurs sont comparées.
Mais n'oublie pas ceci non plus:
EXISTS
s'exécute à grande vitesse contre IN
: lorsque le résultat de la sous-requête est très volumineux.IN
prend de l'avance sur EXISTS
: lorsque le résultat de la sous-requête est très petit.Référence à pour plus de détails:
La méthode 2 est rapide car elle utilise l'opérateur EXISTS
, où je MySQL
ne charge aucun résultat . Comme indiqué également dans votre lien -docs , elle omet tout ce qui figure dans la clause SELECT
. Il vérifie uniquement la première valeur correspondant aux critères, une fois trouvé, il définit la condition TRUE
et est déplacé pour un traitement ultérieur.
De l’autre côté, la méthode 1 a l’opérateur IN
qui charge toutes les valeurs possibles et les met en correspondance. La condition est définie sur TRUE
uniquement lorsque la correspondance exacte est trouvée, ce qui prend du temps.
Par conséquent, votre méthode 2 est rapide.
J'espère que ça aide...
L'opérateur EXISTE est un opérateur booléen qui renvoie true ou false. L'opérateur EXISTS est souvent utilisé dans une sous-requête pour rechercher une condition «exist».
SELECT
select_list
FROM
a_table
WHERE
[NOT] EXISTS(subquery);
Si la sous-requête renvoie une ligne, l'opérateur EXISTE renvoie true, sinon il renvoie false.
De plus, l'opérateur EXISTE met fin au traitement ultérieur dès qu'il trouve une ligne correspondante. En raison de cette caractéristique, vous pouvez utiliser l'opérateur EXIST pour améliorer les performances de la requête dans certains cas.
L'opérateur NOT nie l'opérateur EXISTE. En d'autres termes, NOT EXISTS renvoie true si la sous-requête ne renvoie aucune ligne, sinon elle renvoie false.
Vous pouvez utiliser SELECT *, la colonne SELECT, SELECT a_constant ou n’importe quoi de la sous-requête. Les résultats sont les mêmes car MySQL ignore le select_list qui apparaît dans la clause SELECT.
La raison en est que l’opérateur EXISTE fonctionne selon le principe «au moins trouvé». Il renvoie true et arrête l'analyse de la table une fois au moins une ligne correspondante trouvée.
D'autre part, lorsque l'opérateur DANS est combiné à une sous-requête, MySQL doit d'abord traiter la sous-requête, puis utilise le résultat de la sous-requête pour traiter la totalité de la requête.
La règle générale est que si la sous-requête contient un grand volume de données, l'opérateur EXISTE fournit de meilleures performances.
Toutefois, la requête utilisant l'opérateur DANS s'exécutera plus rapidement si le jeu de résultats renvoyé par la sous-requête est très petit.
Pour des explications détaillées et des exemples: MySQL EXISTS - mysqltutorial.org _
La deuxième méthode est plus rapide parce que vous avez ceci comme ici "WHERE t3.reservation_id = t.reservation_id". Dans le premier cas, votre sous-requête doit effectuer une analyse complète dans la table pour vérifier les informations. Cependant, à la méthode 2o, la sous-requête sait exactement ce qu'elle recherche et, une fois trouvée, est vérifiée si elle a la condition.