web-dev-qa-db-fra.com

Sous-requêtes avec EXISTS vs IN - MySQL

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
         )                                             
   )
20
Techie

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:

46
bonCodigo

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

3
Shubhansh

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 _

1
ktnam

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. 

0
medina