web-dev-qa-db-fra.com

Améliorer ou optimiser une requête très lente

J'ai une base de données assez grande - 113 299 lignes dans wp_posts et 216 06649 lignes dans wp_postmeta.

Une des requêtes personnalisées que j'exécute après l'ajout ou la modification d'une publication est affichée dans le fichier de journal lent de MySQL chaque fois qu'elle est exécutée - et semble prendre beaucoup trop de secondes (entre 17 et 78 secondes en fait).

Voici à quoi cela ressemble dans query_posts:

    $args = array( 
                'meta_query' => array(
                                    array(
                                        'key' => 'article_template',
                                        'value' => 'news',
                                    ),
                                ),
                'posts_per_page' => '30',
                'category__in' => array( 3, 4, 5 ),
                'post_status' => 'publish',
                'no_found_rows' => true,
                'orderby' => 'meta_value',
                'meta_key' => 'article_datetime',
                'order' => 'DESC'
            );
    query_posts( $args );

Et voici à quoi cela ressemble dans le fichier de journal lent de MySQL:

SELECT   wp_posts.ID FROM wp_posts  INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) WHERE 1=1  AND ( wp_term_relationships.term_taxonomy_id IN (3,4,5) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') AND (wp_postmeta.meta_key = 'article_datetime'
AND  (mt1.meta_key = 'article_template' AND CAST(mt1.meta_value AS CHAR) = 'news') ) GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value DESC LIMIT 0, 30;

Voici ce que EXPLAIN montre pour cette requête:

mysql> explain SELECT   wp_posts.ID FROM wp_posts  INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
    -> INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) WHERE 1=1  AND ( wp_term_relationships.term_taxonomy_id IN (3,4,5) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') AND (wp_postmeta.meta_key = 'article_datetime' AND  (mt1.meta_key = 'article_template' AND CAST(mt1.meta_value AS CHAR) = 'news') ) GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value DESC LIMIT 0, 30;
+----+-------------+-----------------------+--------+--------------------------+----------+---------+-----------------------------+-------+----------------------------------------------+
| id | select_type | table                 | type   | possible_keys            | key      | key_len | ref                         | rows  | Extra                                        |
+----+-------------+-----------------------+--------+--------------------------+----------+---------+-----------------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | wp_postmeta           | ref    | post_id,meta_key         | meta_key | 768     | const                       | 98576 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | wp_posts              | eq_ref | PRIMARY,type_status_date | PRIMARY  | 8       | toi_web.wp_postmeta.post_id |     1 | Using where                                  |
|  1 | SIMPLE      | mt1                   | ref    | post_id,meta_key         | post_id  | 8       | toi_web.wp_postmeta.post_id |    11 | Using where                                  |
|  1 | SIMPLE      | wp_term_relationships | ref    | PRIMARY,term_taxonomy_id | PRIMARY  | 8       | toi_web.mt1.post_id         |     2 | Using where; Using index                     |
+----+-------------+-----------------------+--------+--------------------------+----------+---------+-----------------------------+-------+----------------------------------------------+

Je me demande donc si quelqu'un a un bon conseil ou une suggestion pour l'optimiser et éviter la requête lente? Peut-être que casser cela dans une boucle query_posts différente? Ou tout d’abord, récupérez les ID des publications avec une simple requête wpdb->get_results?

Je suis ouvert à toute suggestion :)

À propos, nous avons un cluster MySQL très robuste, donc les ressources du serveur ne sont pas le problème .

3
Biranit Goren
  1. Pour que "article_datetime" soit une valeur numérique, je suggérerais qu'au lieu d'utiliser 'orderby' => 'meta_value', utilisez 'orderby' => 'meta_value_num'
  2. Si la requête est toujours lente, alors supprimez:

    'orderby' => 'meta_value', 'meta_key' => 'article_datetime', 'order' => 'DESC'

et au lieu de cela trier le résultat dans php.

2
Fiaz Husyn