J'essaie de récupérer 5 résultats de travaux par page (j'utilise silex avec doctrine), mais le chargement de la page prend environ 30 à 40 secondes.

  $sql = "
            SELECT jobs.ID, jobs.date_added, jobs.user, jobs.title, jobsmeta.meta_value, jobs_locations_rel.county, jobs_locations_rel.city, usersmeta.meta_value, attachments.title
            FROM jobs
                JOIN jobsmeta
                    ON jobsmeta.parent_id = jobs.ID
                JOIN jobs_locations_rel
                    ON jobs_locations_rel.parent_id = jobs.ID
                JOIN usersmeta
                    ON usersmeta.parent_id = jobs.user
                JOIN attachments
                    ON attachments.ID = (SELECT meta_value FROM usersmeta WHERE parent_id = jobs.ID AND meta_key = 'user_avatar' LIMIT 1)
                ORDER BY jobs.date_added DESC LIMIT 5";
            $data = $app['db']->fetchAll($sql);

Ce serait le plan explicatif: entrez la description de l'image ici Comment optimiser cette requête pour obtenir le résultat dans un délai plus court?

0
user4015001 24 déc. 2015 à 17:45

2 réponses

Meilleure réponse

Le plan d'exécution montre que seuls deux index (clé primaire) sont utilisés. Cela devrait être amélioré. En dehors des index de clé primaire, vous devriez essayer avec des index supplémentaires sur:

  • emplois (utilisateur)
  • jobsmeta (id_parent)
  • jobs_locations_rel (id_parent)
  • usersmeta (parent_id, meta_key)

La requête est probablement également ralentie par la sous-requête, qui a un LIMIT 1 particulier. Cela signifie que l'enregistrement qu'il récupère peut être aléatoire parmi plusieurs. Cela signifie soit que la conception de votre base de données est insuffisante, soit que vous ne vous souciez pas d'afficher tous les enregistrements associés de la table pièces jointes . Utiliser IN (SELECT ...) sans LIMIT vous assurerait d'avoir tous ces enregistrements pièces jointes .

Mais mieux que d'utiliser IN, c'est de transformer cela en un JOIN supplémentaire, comme ceci:

SELECT   jobs.ID, jobs.date_added, jobs.user, jobs.title,
         jobsmeta.meta_value,
         jobs_locations_rel.county, jobs_locations_rel.city,
         m1.meta_value, attachments.title
FROM     jobs
JOIN     jobsmeta
      ON jobsmeta.parent_id = jobs.ID
JOIN     jobs_locations_rel
      ON jobs_locations_rel.parent_id = jobs.ID
JOIN     usersmeta m1
      ON m1.parent_id = jobs.user
JOIN     usersmeta m2
      ON m2.parent_id = jobs.ID
     AND m2.meta_key = 'user_avatar'
JOIN     attachments
      ON attachments.ID = m2.meta_value
ORDER BY jobs.date_added DESC
LIMIT 5

Autre chose particulière: usersmeta.parent_id fait référence à une valeur jobs.ID ou jobs.user. Cela ressemble à une autre faille dans la conception de la base de données que vous voudrez peut-être examiner.

Si l'ordre des valeurs 'job.id' est le même que l'ordre de jobs.date_added, vous pouvez envisager de faire un ORDER BY jobs.id DESC. Sinon, envisagez de créer un index sur jobs(date_added).

Enfin, votre order by n'est pas assez spécifique, car il permet un ordre de tri arbitraire pour les enregistrements qui partagent le même jobs.id. Ce n'est pas lié aux performances, mais je pense que cela pourrait rendre la pagination difficile (selon la façon dont vous l'avez implémentée). Le mieux serait d'avoir une combinaison de colonnes répertoriées dans la clause ORDER BY qui, ensemble, identifient de manière unique l'enregistrement dans le résultat.

1
trincot 25 déc. 2015 à 18:28

Vous pouvez activer le cache de requêtes mysql pour des requêtes répétées plus rapides.

0
HasanCseBuet 24 déc. 2015 à 15:19