web-dev-qa-db-fra.com

Quelqu'un peut-il expliquer pourquoi le reste rejoindre deux vues dans MySQL est si lent?

Voici une question que j'ai posée hier - https://stackoverflow.com/questions/22180727/left-joining-two-views-is-slow .

J'ai une bonne réponse qui m'a aidé mais je ne comprends pas pourquoi la jointure gauche est tellement plus lente que la recherche. L'accocation de gauche était de 16 secondes - et je suis à peu près sûr que mes tables sont d'au moins 90% optimisées - et lorsque vous faites la recherche, il suffit de .14 secondes. Quand j'ai laissé des tables de jointure, ce n'est pas si lent alors pourquoi vues?

7
LOSTinDB

Selon la MySQL Documentation sur Vues

Vues (y compris les vues mises à jour) sont disponibles dans MySQL Server 5.6. Les vues sont des requêtes stockées lorsqu'ils sont invoqués produisent un ensemble de résultats. Une vue agit comme une table virtuelle.

La première chose qui doit être réalisée à propos d'une vue est qu'elle produit un ensemble de résultats. Le jeu de résultats émergeant de la requête invoquée à partir de la vue est une table virtuelle car elle est créée à la demande. Il n'y a pas de DDL que vous pouvez invoquer ensuite pour indexer immédiatement le jeu de résultats. À toutes fins utiles, le jeu de résultats est une table sans index. En effet, la jointure gauche que vous exécutions est essentiellement un produit cartésien avec un peu de filtrage.

Pour vous donner un regard plus granulaire sur la jointure de deux points de vue, je vous référerai à un poste que j'ai fait l'année dernière expliquant les mécanismes internes MySQL utilise pour évaluer les jointures et la suivante ( y a-t-il une différence d'exécution entre une condition de jointure et un endroit où condition ? ). Je vais vous montrer le mécanisme tel que publié dans Comprendre MySQL Internals (page 172):

  • Déterminez quelles clés peuvent être utilisées pour récupérer les enregistrements des tables et choisir le meilleur pour chaque table.
  • Pour chaque table, décidez si une analyse de table est meilleure que la lecture sur une clé. S'il y a beaucoup d'enregistrements correspondant à la valeur clé, les avantages de la clé sont réduits et la numérisation de la table devient plus rapide.
  • Déterminez l'ordre dans lequel les tableaux doivent être joints lorsque plusieurs tables sont présentes dans la requête.
  • Réécrivez les clauses pour éliminer le code mort, réduisant les calculs inutiles et modifier les contraintes dans la mesure du possible à l'ouverture de la voie à l'utilisation des touches.
  • Éliminez les tables non utilisées de la jointure.
  • Déterminez si les clés peuvent être utilisées pour ORDER BY et GROUP BY.
  • Essayez de simplifier les sous-sollicitations, ainsi que de déterminer dans quelle mesure leurs résultats peuvent être mis en cache.
  • Fusionner des vues (élargir la référence de vue en tant que macro)

OK, il semble que des index soient utilisés. Cependant, regarde plus près. Si vous remplacez le mot View pour Table, regardez ce qui arrive à l'exécution du mécanisme:

Mécanisme modifié

  • Déterminez quelles touches peuvent être utilisées pour extraire les enregistrements de views et choisissez le meilleur pour chaque view.
  • Pour chacun view, décidez si un view Scan est mieux que lire sur une clé. S'il y a beaucoup d'enregistrements correspondant à la valeur de la clé, les avantages de la clé sont réduits et le view Scan devient plus rapide.
  • Déterminez la commande dans laquelle views doit être jointe lorsque plusieurs views est présent dans la requête.
  • Réécrivez les clauses pour éliminer le code mort, réduisant les calculs inutiles et modifier les contraintes dans la mesure du possible à l'ouverture de la voie à l'utilisation des touches.
  • Éliminer inutilisé views de la jointure.
  • Déterminez si les clés peuvent être utilisées pour ORDER BY et GROUP BY.
  • Essayez de simplifier les sous-sollicitations, ainsi que de déterminer dans quelle mesure leurs résultats peuvent être mis en cache.
  • Fusionner des vues (élargir la référence de vue en tant que macro)

Chaque table (vue) n'a aucun index. Ainsi, travailler avec des tables virtuelles, des tables temporaires ou des tables sans index ne devient vraiment indistincte lors d'une jointure. Les clés utilisées ne sont que pour les opérations de jointure, pas tant pour la recherche de choses plus rapidement.

Pensez à Votre requête En choisissant deux livres téléphoniques, les pages jaunes de 2014 et les pages jaunes de 2013. Chaque livre de pages jaunes contient les pages blanches pour les numéros de téléphone résidentiels.

  • Fin 2012, une table de base de données a été utilisée pour générer les pages jaunes de 2013.
  • En 2013
    • Les gens ont changé de numéros de téléphone
    • Les gens ont reçu de nouveaux numéros de téléphone
    • Les gens ont abandonné les numéros de téléphone, passant au téléphone portable
  • Fin 2013, une table de base de données a été utilisée pour générer les pages jaunes de 2014.

De toute évidence, il y a des différences entre les deux livres téléphoniques. Faire une participation de tables de base de données pour déterminer les différences entre 2013 et 2014 ne devrait poser aucun problème.

Imaginez la fusion des deux livres téléphoniques à la main pour localiser les différences. Cela semble fou, n'est-ce pas? Nonobstant, c'est exactement ce que vous demandez à MySQLD de faire lorsque vous vous joignez à deux points de vue. N'oubliez pas que vous ne rejoignez pas de vraies tables et il n'y a pas d'index à piggyback.

Maintenant, regardons en arrière la requête.

SELECT DISTINCT
viewA.TRID, 
viewA.hits,
viewA.department,
viewA.admin,
viewA.publisher,
viewA.employee,
viewA.logincount,
viewA.registrationdate,
viewA.firstlogin,
viewA.lastlogin,
viewA.`month`,
viewA.`year`,
viewA.businesscategory,
viewA.mail,
viewA.givenname,
viewA.sn,
viewA.departmentnumber,
viewA.sa_title,
viewA.title,
viewA.supemail,
viewA.regionname
FROM
viewA
LEFT JOIN viewB ON viewA.TRID = viewB.TRID
WHERE viewB.TRID IS NULL 

Vous utilisez une table virtuelle (table sans index), Viewa, y rejoignant une autre table virtuelle, Viewb. La table temporaire étant générée par intermittence serait aussi grande que la vie. Ensuite, vous exécutez un tri interne sur la grande table Temp pour le rendre distinct.

ÉPILOGUE

Compte tenu des mécanismes internes d'évaluation des joints, le long de la nature transitoire et sans index de l'ensemble de résultats d'une vue, votre requête d'origine (jointure de gauche de deux vues) devrait devenir des heures d'exécution des ordres de grandeur. Dans le même temps, le Réponse que vous avez obtenu de Stackoverflow devrait bien fonctionner, étant donné le même algorithme de jointure que je viens de décrire.

J'espère que les détails de Gory, je viens de poster des réponses de votre question sur la raison.

10
RolandoMySQLDBA