web-dev-qa-db-ja.com

カスタム投稿タイプのWP_Queryが遅い

私は注文の投稿がある不動産のテーマがあります。 Postには、価格や場所などの分類法など、多くのメタ値があります。私はこれのために検索エンジンを作成しました、しかし、問い合わせは実行するのにばかげて長い時間がかかります。

データベースには50個のプロパティしかありませんが、wp_postmetaテーブルには20044行あります。

30秒以上かかるサンプルクエリ

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

そしてこれがWP_Queryに渡される$ argsテーブルです。

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)

これがEXPLAINの結果です。

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

私は多くの関連する質問を読みましたが、それをシードするためにクエリを変更するために熱いと説明している答えを見つけることができません。

ありがとう

編集:

0.01秒の速度で同じ値を返すように見えるカスタムSQLを作成しました。

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

今度はadd_filter( 'posts_where' , 'posts_where_statement' );を使って、すべてのmeta_query(パフォーマンスの問題を引き起こす)をカスタムSQLとして追加します。

1
Johnny

これはWordPressとpostmetaが関係する検索に関する既知の問題です。

私がやろうとしているのは、あなたが通常最も探している「もの」のための新しい分類法を作成することです:

  • offer_order_statusはアクティブでもそうでなくてもよいので、よりよい候補のようです。 2つの要素からなる分類法を作成したいと思います。それはあなたの検索の時間をかなり減らすでしょう
  • それでも十分でない場合は、次に使用する他の2つの「メタ」に対して「バケット」を定義し、それらに分類法を作成します。バケツはさまざまな方法で作成することができます。「サイズ」分類法を> 100000、別のものを> 200000などにすることができます。そして価格の場合は、< 100000> 100000 && < 200000を実行します。それは本当にあなたがどのように検索を計画しているかにかかっています。

ステップ2の要点は、投稿の保存アクションにフックしてそのプロパティの領域/サイズを「読む」ことができ、そしてそれに適した分類法を選びバックエンドに自動的に追加できるということです。それを行うことによって、以下の利点が得られます。a)分類法を常に実際のメタ値と同期させること(「同じ」または類似の情報を複数回追加することは避けたい)。 b)分類基準の「バケツ」をいつでも変更して「新しい」ニーズを満たすことができます。これらのフィールドには真の価値があるので、正しい分類法を取得するにはすべての投稿を再度「保存」する必要があります。 (そしてあなたはそれをプログラム的に行うことができます)。 c)分類法ベースの検索は、メタ検索よりもはるかに高速です(postmetaと比較して、索引付きの比較的小さい表です)。


2番目のアプローチは、この場合はうまくいきませんが、それでもオプションですが、postmetaテーブルにインデックスを追加し、post_id、meta_key、meta_valueによるインデックスを作成することです。これはインデックスを使うことでクエリを高速化するでしょうが、おそらくそれほど速くはありません。

しかし、以前のものよりも実装がはるかに簡単なので、私はおそらく最初にこの2番目のオプションを実装し、それがどのようになるかを見ることを試みるでしょう。

1
Xavi Ivars

1日あたりの変更量がそれほど大きくないと仮定すると、照会に適した形式で "シャドウDB"を作成できます。たとえば、各属性に独自の列があり、保存後に毎回更新します。

このアプローチの利点は、post/meta/termsの使用法、adminの変更、およびフロントエンドの変更を何も変更する必要がないことです。データを調整するためにコードを記述する必要があるという欠点があります。すべての投稿と一時保存はコードを書く際に、そしてそれぞれの更新でDBサーバーにいくらかあなたのためにもう少しの仕事を作成するでしょう。

0
Mark Kaplun