Question

J'ai besoin d'optimiser la requête suivante:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50

EXPLIQUEZ SELECT me donne le résultat suivant:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where

Pourquoi il ne prend d'abord les articles, puis les BlogPosts? Est-ce parce blogposts ont plus d'entrées? Et comment puis-je améliorer la requête afin que le articlepost peut utiliser un indice?

Mise à jour: Un index est mis sur blogposts.date_created. Retrait de la blogposts.title condition LIKE et la date_published <= NOW () ne fait rien.

Lorsque je supprime la " articles.id AS articleid " il peut utiliser l'indice blogpost_id sur les articles ... Ça a l'air étrange pour moi, quelqu'un sait pourquoi? (Parce que je dois réellement ..)

nouvelle expliquer ressemble à ceci:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  articles    index blogpost_id blogpost_id    4    NULL    6915    Using index; Using temporary; Using filesort
1   SIMPLE  blogposts   eq_ref  PRIMARY PRIMARY 4   articles.blogpost_id    1   Using where
Était-ce utile?

La solution

J'ai regardé de plus près la question et vous pourriez être en mesure de le redessiner. Voici ce que je veux dire:

La partie LIMIT 0,50 de la requête semble être fait occupée dans la requête précédente.

Vous pouvez améliorer la mise en page de la requête en procédant comme suit:

Étape 1) Créer une requête en ligne pour recueillir les clés seulement. Dans ce cas, l'id pour blogposts.

Étape 2) Imposer une quelconque WHERE, ORDER BY clauses GROUP BY et sur la demande de recherche en ligne qui porte clés.

Étape 3) Imposte la clause LIMIT comme la dernière étape consistant à effectuer une recherche en ligne.

Étape 4) Joignez-vous à la requête en ligne avec la table blogpost dans le cas où vous avez besoin des colonnes supplémentaires de blogpost comme blostpost temptable

Étape 5) Joignez-vous à cette nouvelle blogpost temptable avec la table des articles.

Les étapes 1-3 est destiné à créer un temptable avec exactement 50 lignes et inclure l'ID blogpost. Ensuite, effectuer tous JOIN bon dernier.

Avec ces étapes appliquées à votre requête initiale, vous devriez avoir ceci:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
  SELECT B.*
  FROM
  (
    SELECT id FROM blogposts
    WHERE date_published <= NOW()
    AND deleted = 0 AND visible = 1
    AND title LIKE '%{de}%'
    ORDER BY date_created DESC
    LIMIT 0,50
  ) A
  INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;

Depuis que vous avez modifié la question et déclaré que vous allez supprimer LIKE, maintenant votre requête devrait ressembler à ceci:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
  SELECT B.*
  FROM
  (
    SELECT id FROM blogposts
    WHERE date_published <= NOW()
    AND deleted = 0 AND visible = 1
    ORDER BY date_created DESC
    LIMIT 0,50
  ) A
  INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;

Dans l'expression [choses omis], si vous n'avez pas besoin de quoi que ce soit que les autres blogposts clés, votre requête devrait ressembler à ceci:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
  SELECT id FROM blogposts
  WHERE date_published <= NOW()
  AND deleted = 0 AND visible = 1
  ORDER BY date_created DESC
  LIMIT 0,50
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;

CAVEAT

Assurez-vous que vous construisez un index qui implique les colonnes supprimées, visibles et DATE_CREATED comme suit:

ALTER TABLE blogposts ADD INDEX deleted_visible_date_created (deleted,visible,date_created);

Lui donner un essai !!!

Autres conseils

Votre où blogposts.title LIKE '%{de}%' état provoque une analyse complète de la table sur la table blogposts . Il est des chiffres de MySQL probablement balayage 6915 articles est plus efficace.

Quant à la façon de l'améliorer, vous pouvez ajouter un index sur blogposts en utilisant le date_created ou date_published et ajouter une plage du à la condition where (autre chose que <= NOW ())

ET blogposts.title LIKE '% {de}%' - Inutile pour l'optimisation (leader wild card)

OÙ blogposts.deleted = 0 ET blogposts.visible = 1 - Beurk. Si elles ne doivent pas être présentés, les sortir de la table

blogposts.date_published <= NOW () ORDER BY blogposts.date_created DESC LIMIT 0, 50 - Cela conduit à besoin INDEX (date_published) (Cependant, LIKE et drapeaux peuvent empêcher cet indice d'être utilisé.)

S'il vous plaît fournir SHOW CREATE TABLE ...; TABLE SHOW STATUS ...;

Merci beaucoup:)

je lui ai donné un essai et a découvert, que fait votre dernier commentaire au sujet de l'indice était la chose dont je avais besoin. Parfois, il est juste une petite amélioration qui est nécessaire ...;) Comparaison:

Old Interrogation:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50

Nouvelle recherche:

SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
    SELECT B.*
    FROM
    (
        SELECT id FROM blogposts
        WHERE date_published <= NOW()
        AND deleted = 0 AND visible = 1
        AND title LIKE '%{de}%'
        ORDER BY date_created DESC
        LIMIT 0,50
    ) A
    INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id

sans l'indice mentionné:

Old Expliquez Résultat:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where

Nouveau Expliquez Résultat:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    50   
1   PRIMARY     articles    ref     blogposts_id    blogposts_id    4   blogposts.id    1    
2   DERIVED     <derived3>  ALL     NULL    NULL    NULL    NULL    50   
2   DERIVED     B   eq_ref  PRIMARY     PRIMARY     4   A.id    1    
3   DERIVED     blogposts   ALL     deleted,visible,date_published  deleted     1       28198   Using filesort

Expliquez résultat avec l'index sur l'ancienne requête:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  blogposts   ref     PRIMARY,deleted,visible,date_published,deleted_vis...   deleted_visible_date_created    2   const,const     27771   Using where
1   SIMPLE  articles    ref     blogposts_id    blogposts_id    4   db.blogposts.id     1

Expliquez résultat avec l'index sur la nouvelle requête:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    50   
1   PRIMARY     articles    ref     blogposts_id    blogposts_id    4   blogposts.id    1    
2   DERIVED     <derived3>  ALL     NULL    NULL    NULL    NULL    50   
2   DERIVED     B   eq_ref  PRIMARY     PRIMARY     4   A.id    1    
3   DERIVED     blogposts   ref     deleted,visible,date_published,deleted_visible_dat...   deleted_visible_date_created    2       27771   Using where

Vitesse sur l'ancienne requête sans / avec l'index: 0,1835 / 0,0037

Vitesse sur la nouvelle requête sans / avec l'index: 0,1883 / 0,0035

Donc à cause de la differency juste marginale entre l'ancienne / nouvelle requête, je préfère toujours utiliser l'ancienne requête, mais avec l'index. Mais je garderai cela à l'esprit, comme si un jour l'ancienne requête est trop lent:)

Quel serait intéressant pour moi est de savoir, comment vous avez eu l'idée de mettre l'index comme celui-ci? Je pense que je publiais cette question, j'ai essayé aussi avec deleted_visible mais au lieu de je date_created utilisé date_published (comme il est dans la clause where) ...

Merci:)

Mise à jour par RolandoMySQLDBA 2011-05-19 13:03

Ce qu'il trahissait m'a été les clauses WHERE et ORDER BY.

Dans la clause WHERE, supprimé (0) et visible (1) sont des valeurs statiques. Dans la clause ORDER BY, l'ensemble date_created était comme une cible mobile entre les lignes avec supprimé = 0 et visible = 1. Donc, j'ai placé les variables statiques devant l'index, puis la cible mobile dans l'index dernier. En général, cela fait partie du principe sous-jacent de refactorisation instructions SQL. Vous avez besoin d'indices qui soutiendront votre WHERE, GROUP BY et clauses ORDER.

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top