web-dev-qa-db-fra.com

WP_Query lent pour le type de publication personnalisé

J'ai un thème immobilier avec post personnalisé: propriétés. Post a de nombreuses méta-valeurs telles que le prix et la taxonomie, comme l'emplacement. J'ai créé un moteur de recherche pour cela, mais les requêtes prennent une quantité de temps ridicule à exécuter.

Je n'ai que 50 propriétés dans la base de données, mais la table wp_postmeta a 20044 lignes.

Exemple de requête, qui prend plus de 30 ans:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
LEFT JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_relationships AS tt1
ON (wp_posts.ID = tt1.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 )
INNER JOIN wp_postmeta AS mt2
ON ( wp_posts.ID = mt2.post_id )
INNER JOIN wp_postmeta AS mt3
ON ( wp_posts.ID = mt3.post_id )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (6)
AND tt1.term_taxonomy_id IN (19,287) )
AND ( wp_postmeta.meta_key = 'featured'
AND ( ( mt1.meta_key = 'area'
AND CAST(mt1.meta_value AS SIGNED) <= '100000' )
AND ( mt2.meta_key = 'price'
AND CAST(mt2.meta_value AS SIGNED) <= '4433356' )
AND ( mt3.meta_key = 'offer_order_status'
AND mt3.meta_value = 'active' ) ) )
AND wp_posts.post_type = 'property'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value+0 DESC
LIMIT 0, 12

Et voici la table $ args passée à la WP_Query:

array (size=7)
  'post_type' => string 'property' (length=18)
  'paged' => int 1
  'meta_key' => string 'featured' (length=21)
  'orderby' => string 'meta_value_num' (length=14)
  'order' => string 'DESC' (length=4)
  'tax_query' => 
    array (size=3)
      0 => 
        array (size=3)
          'taxonomy' => string 'property_type' (length=13)
          'field' => string 'id' (length=2)
          'terms' => string '6' (length=1)
      1 => 
        array (size=3)
          'taxonomy' => string 'transaction_type' (length=16)
          'field' => string 'id' (length=2)
          'terms' => 
            array (size=2)
              0 => string '19' (length=2)
              1 => string '287' (length=3)
      'relation' => string 'AND' (length=3)
  'meta_query' => 
    array (size=4)
      0 => 
        array (size=4)
          'key' => string 'area' (length=17)
          'value' => int 100000
          'type' => string 'NUMERIC' (length=7)
          'compare' => string '<=' (length=2)
      1 => 
        array (size=4)
          'key' => string 'price' (length=18)
          'value' => int 4433356
          'type' => string 'NUMERIC' (length=7)
          'compare' => string '<=' (length=2)
      'relation' => string 'AND' (length=3)
      2 => 
        array (size=3)
          'key' => string 'offer_order_status' (length=31)
          'value' => string 'active' (length=6)
          'compare' => string '=' (length=1)

Voici EXPLAIN résultat:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra   
1   SIMPLE  wp_term_relationships   ref     PRIMARY,term_taxonomy_id    term_taxonomy_id    8   const   19  Using where; Using index; Using temporary; Using filesort
1   SIMPLE  wp_posts    eq_ref  PRIMARY,post_name,type_status_date,post_parent,post_author  PRIMARY     8   wp_real_estate3.wp_term_relationships.object_id     1   Using where
1   SIMPLE  tt1     ref     PRIMARY,term_taxonomy_id    PRIMARY     8   wp_real_estate3.wp_term_relationships.object_id     2   Using where; Using index
1   SIMPLE  mt3     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where
1   SIMPLE  mt1     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where
1   SIMPLE  mt2     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where
1   SIMPLE  wp_postmeta     ref     post_id,meta_key    post_id     8   wp_real_estate3.wp_term_relationships.object_id     12  Using where

J'ai lu de nombreuses questions connexes, mais je ne trouve aucune réponse décrivant "à chaud" pour changer la requête afin de l'amorcer.

Merci

MODIFIER:

J'ai créé un code SQL personnalisé qui semble renvoyer les mêmes valeurs avec la vitesse de 0.01s:

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
LEFT JOIN wp_term_relationships
ON (wp_posts.ID = wp_term_relationships.object_id)
LEFT JOIN wp_term_relationships AS tt1
ON (wp_posts.ID = tt1.object_id)
INNER JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (6)
AND tt1.term_taxonomy_id IN (19,287) )
AND ( wp_postmeta.meta_key = 'apartment_wp_featured' )
AND wp_posts.post_type = 'apartment_property'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private')
AND wp_posts.ID IN (
                        SELECT post_id from wp_postmeta
                        WHERE ((meta_key = 'apartment_wp_area' AND CAST(meta_value AS SIGNED) < '100000')
                        or (meta_key = 'apartment_wp_price' AND CAST(meta_value AS SIGNED) < '4433356')
                        or (meta_key = 'apartment_wp_offer_order_status' AND meta_value = 'active'))
                )
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value+0 DESC
LIMIT 0, 12

Maintenant, je vais essayer d’ajouter toutes les meta_query (ce qui pose des problèmes de performances) en tant que SQL personnalisé avec add_filter( 'posts_where' , 'posts_where_statement' );.

1
Johnny

C'est un problème connu avec WordPress et les recherches impliquant postmeta.

Ce que j'essayerais de faire, c'est de créer une nouvelle taxonomie pour les "choses" que vous recherchez habituellement:

  • offer_order_status semble être le meilleur candidat, qu'il soit actif ou non. Je créerais une taxonomie avec deux éléments. Cela réduirait considérablement le temps de votre recherche
  • Si cela ne suffisait pas, la prochaine étape que j'essaierais probablement est de définir des "compartiments" pour les deux autres "méta" que vous utilisez et de créer des taxonomies: la surface et le prix. Les compartiments peuvent être créés de différentes manières: vous pouvez avoir une taxonomie de "taille" qui était > 100000, une autre > 200000, etc., puis pour les prix, vous pouvez choisir de faire < 100000, > 100000 && < 200000. Cela dépend vraiment de la façon dont vous prévoyez de chercher.

Le point essentiel pour la deuxième étape est que vous pouvez vous connecter à l'action de sauvegarde du message pour "lire" quelle est l'aire/la taille de cette propriété, puis choisir les taxonomies appropriées et les ajouter automatiquement dans le back-end. En faisant cela, vous obtenez l'avantage de: a) avoir les taxonomies toujours en phase avec la méta valeur réelle (vous ne voulez pas que les gens ajoutent "la même" ou des informations similaires plus d'une fois). b) vous pouvez changer les "compartiments" des taxonomies à tout moment pour répondre à vos "nouveaux" besoins: comme vous avez la valeur réelle pour ces champs, il vous suffit de "sauvegarder" à nouveau tous les posts pour obtenir les taxonomies appropriées (et vous pouvez le faire par programmation). c) la recherche basée sur la taxonomie est beaucoup plus rapide que la méta-recherche (est une table indexée et relativement petite, par rapport à postmeta)


Une deuxième approche, qui ne fonctionnera pas très bien dans ce cas, mais qui reste une option, consiste à ajouter des index à la table postmeta, en indexant par post_id, meta_key et meta_value. Cela accélérera également la requête en utilisant des index, mais probablement pas autant.

Mais comme il est beaucoup plus facile à mettre en œuvre que le précédent, j'essaierais probablement de mettre en œuvre cette deuxième option en premier et de voir comment ça se passe.

1
Xavi Ivars

En supposant que la quantité de modifications ne soit pas importante par jour, vous pouvez créer une "base de données fantôme" dans un format plus agréable à interroger, par exemple, chaque attribut possède sa propre colonne et la mettre à jour à chaque sauvegarde de publication.

L’avantage de cette approche est que vous n’aurez rien à changer dans votre utilisation de post/meta/terms, aucun changement dans admin, ni dans front-end. L’inconvénient est que vous devez écrire le code pour ajuster les données sur chaque publication et chaque sauvegarde, ce qui créera encore un travail supplémentaire lors de l’écriture du code, ainsi que pour le serveur de base de données à chaque mise à jour.

0
Mark Kaplun