2010-08-25 7 views
1

J'utilise actuellement la requête suivante pour jsPerf. Dans le cas probable vous ne connaissez pas jsPerf - il y a deux tables: pages contenant les cas de test/révisions, et tests contenant les extraits de code pour les tests dans les cas de test. Il existe actuellement 937 enregistrements dans pages et 3817 enregistrements dans tests.Comment optimiser cette requête MySQL à faible performance?

Comme vous pouvez le voir, il faut un certain temps pour charger the “Browse jsPerf” page où cette requête est utilisée.

La requête prend environ 7 secondes pour exécuter:

SELECT 
id AS pID, 
slug AS url, 
revision, 
title, 
published, 
updated, 
(
    SELECT COUNT(*) 
    FROM pages 
    WHERE slug = url 
    AND visible = "y" 
) AS revisionCount, 
(
    SELECT COUNT(*) 
    FROM tests 
    WHERE pageID = pID 
) AS testCount 
FROM pages 
WHERE updated IN (
    SELECT MAX(updated) 
    FROM pages 
    WHERE visible = "y" 
    GROUP BY slug 
) 
AND visible = "y" 
ORDER BY updated DESC 

J'ai ajouté des index sur tous les champs qui apparaissent dans WHERE clauses. Devrais-je en ajouter d'autres?

Comment cette requête peut-elle être optimisée?

P.S. Je sais que je pourrais implémenter un système de cache en PHP - je le ferai probablement, alors s'il vous plait, ne me le dites pas :) J'aimerais vraiment savoir comment cette requête pourrait aussi être améliorée.

+0

Avez-vous ajouté un index pour chaque colonne, ou avez-vous ajouter des indices qui combinent des colonnes en fonction de la façon dont ils sont utilisés? Par exemple, je pense qu'un index sur slug AND visible pourrait mieux que deux indices distincts. En fait, vous pourriez avoir besoin de l'index combiné et un autre juste visible. – FrustratedWithFormsDesigner

+0

Assurez-vous que vous avez des index sur les colonnes appropriées. Publiez la sortie d'EXPLAIN sur votre requête. – nos

+0

@FrustratedWithFormsDesigner: Voici les index que j'ai actuellement: Index pour la table 'pages': http://i.imgur.com/msQtn.png Index pour la table' tests': http://i.imgur.com/Zwtb7 .png Notez l'index combiné sur 'slug' et' revision' - devrais-je changer cela en 'slug' et' visible'? –

Répondre

1

Utilisation:

SELECT x.id AS pID, 
      x.slug AS url, 
      x.revision, 
      x.title, 
      x.published, 
      x.updated, 
      y.revisionCount, 
      COALESCE(z.testCount, 0) AS testCount 
    FROM pages x 
    JOIN (SELECT p.slug, 
        MAX(p.updated) AS max_updated, 
        COUNT(*) AS revisionCount 
      FROM pages p 
      WHERE p.visible = 'y' 
     GROUP BY p.slug) y ON y.slug = x.slug 
          AND y.max_updated = x.updated 
LEFT JOIN (SELECT t.pageid, 
        COUNT(*) AS testCount 
      FROM tests t 
     GROUP BY t.pageid) z ON z.pageid = x.id 
ORDER BY updated DESC 
+0

Merci, ça a marché comme un charme! Je n'avais jamais entendu parler de "COALESCE" auparavant. Ces JOINs semblent sûrement plus rapides que les sous-requêtes que j'utilisais auparavant. –

+1

@Mathias Bynens: Si vous ne pouvez pas les battre, JOIN 'em =) –

0

Vous voudrez peut-être essayer les sous-requêtes une à la fois pour voir laquelle est la plus lente.

Cette requête:

SELECT MAX(updated) 
    FROM pages 
    WHERE visible = "y" 
    GROUP BY slug 

rend trier le résultat par limaces. C'est probablement lent.

+0

La sous-requête que vous avez mentionnée s'exécute en 0.0125 secondes ('stand-alone', c'est-à-dire). Je vais tester les autres maintenant! –

1

Vous souhaitez apprendre à utiliser EXPLAIN. Cela exécutera l'instruction sql et vous montrera quels index sont utilisés et quelles analyses sont effectuées. L'objectif est de réduire le nombre d'analyses de lignes (c.-à-d. La base de données recherchant des valeurs ligne par ligne).

+0

Voici les résultats de 'EXPLAIN [query]': http://i.imgur.com/tOErB.png –

+0

"Le but est de réduire le nombre d'analyses de lignes": Non, ce n'est pas le problème ici. Il a les index dont il a besoin, donc il n'utilisera pas les balayages de table/index. Le problème est dû à un bogue connu dans MySQL. –

Questions connexes