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 faut-il d'abord les articles, puis les blogposts? Est-ce parce que les blogposts ont plus d'entrées? Et comment puis-je améliorer la requête afin que l'articlepost puisse utiliser un index?
Mise à jour : Un index est défini sur blogpostS.date_Created. Supprimer le blogpostS.title comme condition comme et la date_publied <= () ne fait rien.
Quand je supprimai le "articles.ID comme articleId" Il peut utiliser l'index blogpost_id sur les articles ... sonne étrangement pour moi, quelqu'un sait pourquoi? (parce que j'en ai besoin ..)
Le 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
J'ai examiné de plus près la requête et vous pourrez peut-être la repenser. Voici ce que je veux dire:
La limite de 0,50 partie de la requête semble être occupée dans la requête en dernier.
Vous pouvez améliorer la disposition de la requête en procédant comme suit:
Étape 1) Créez une requête en ligne pour ne recueillir que des clés. Dans ce cas, l'ID pour les blogposts.
Étape 2) Imposez-y où, commander et groupe par clauses sur la requête en ligne apportant des clés.
Étape 3) Impostissez la clause limite comme dernière étape consistant à faire la requête en ligne.
Étape 4) Joignez-vous à la requête en ligne avec la table des blogposost dans l'événement que vous avez besoin de colonnes supplémentaires de Blogpost comme plongevest
Étape 5) Rejoignez ce nouveau blogpossique tentable avec la table d'articles.
Les étapes 1 à 3 sont destinées à créer une tentable avec exactement 50 rangées et incluent l'identifiant Blogpost. Ensuite, effectuez toutes les jointures mortes.
Avec ces étapes appliquées à votre requête d'origine, 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 édité la question et indiquez que vous allez supprimer comme si votre requête devrait maintenant ressembler davantage à 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 la phrase [choses omises], si vous n'avez besoin de rien des blogposts autres que les clés, votre requête doit 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 de créer un index impliquant les colonnes supprimées, visibles et Date_Créré comme suit:
ALTER TABLE blogposts ADD INDEX deleted_visible_date_created (deleted,visible,date_created);
Essaie !!!
Votre endroit où condition blogposts.title LIKE '%{de}%'
provoquera une numérisation de table complète sur la table blogposts Tableau. Il est probable que les figures MySQL numérisant 6915 articles sont plus efficaces.
Quant à la manière de l'améliorer, vous pouvez ajouter un index sur blogposts à l'aide de date_created
ou alors date_published
et ajoutez une plage de la condition où l'état (autre que <= maintenant ()))
Et blogpostos.title comme '% {de}%' - inutile pour l'optimisation (carte sauvage principale)
Où blogpostosts.deletted = 0 et blogpost.Visible = 1 - Yuck: S'ils ne devraient pas être affichés, sortez-les de la table.
Et blogposts.date_publihed <= () Commande par blogpost.date_Created Desc Limite 0, 50 - Cela conduit à besoin d'index (Date_Publied) (Cependant, les drapeaux et les drapeaux peuvent empêcher cet index d'être utilisé.)
S'il vous plaît fournir une table de création de spectacle ...; Afficher le statut de table ...;
Merci beaucoup :)
Je l'ai donné un essai et j'ai découvert que votre dernier commentaire sur l'index était la chose dont j'avais besoin. Parfois, ce n'est que quelques petites améliorations nécessaires ...;) Comparaison:
Ancienne requête :
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 requête :
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
Maintenant sans l'indice mentionné:
Ancien expliquant le 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 résultat d'explication :
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
expliquer le résultat avec l'index sur la vieille 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 le 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 la vieille requête sans/avec index : 0.1835/0.0037
Vitesse de la nouvelle requête sans/avec index : 0.1883/0.0035
Ainsi, à cause de la différence marginale juste entre l'ancienne requête/la 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, la vieille requête est trop lente :)
Que serait intéressant pour moi, c'est de savoir comment vous avez eu l'idée de définir l'index comme celui-ci? Je pense que j'ai publié cette question, j'ai également essayé avec deleted_visible, mais au lieu de date_créé, j'ai utilisé date_publihed (comme dans l'endroit où la clause) ...
Merci :)
Mise à jour par Rolandomysqldba 2011-05-19 13:
Ce qui me l'a donné était l'endroit où et l'ordre par des clauses.
Dans la clause où, supprimé (0) et visible (1) sont des valeurs statiques. Dans la clause de l'ordre, la date_created était comme une cible en mouvement parmi toutes les lignes avec supprimées = 0 et visible = 1. Donc, j'ai placé les variables statiques devant l'indice d'abord, puis la cible en mouvement durer dans l'index. Habituellement, cela fait partie du principe sous-jacent de refactoriser les déclarations SQL. Vous avez besoin d'index qui appuiera votre lieu, groupe par et commander des clauses.