私は注文の投稿がある不動産のテーマがあります。 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として追加します。
これはWordPressとpostmetaが関係する検索に関する既知の問題です。
私がやろうとしているのは、あなたが通常最も探している「もの」のための新しい分類法を作成することです:
offer_order_status
はアクティブでもそうでなくてもよいので、よりよい候補のようです。 2つの要素からなる分類法を作成したいと思います。それはあなたの検索の時間をかなり減らすでしょう> 100000
、別のものを> 200000
などにすることができます。そして価格の場合は、< 100000
、> 100000 && < 200000
を実行します。それは本当にあなたがどのように検索を計画しているかにかかっています。ステップ2の要点は、投稿の保存アクションにフックしてそのプロパティの領域/サイズを「読む」ことができ、そしてそれに適した分類法を選びバックエンドに自動的に追加できるということです。それを行うことによって、以下の利点が得られます。a)分類法を常に実際のメタ値と同期させること(「同じ」または類似の情報を複数回追加することは避けたい)。 b)分類基準の「バケツ」をいつでも変更して「新しい」ニーズを満たすことができます。これらのフィールドには真の価値があるので、正しい分類法を取得するにはすべての投稿を再度「保存」する必要があります。 (そしてあなたはそれをプログラム的に行うことができます)。 c)分類法ベースの検索は、メタ検索よりもはるかに高速です(postmetaと比較して、索引付きの比較的小さい表です)。
2番目のアプローチは、この場合はうまくいきませんが、それでもオプションですが、postmetaテーブルにインデックスを追加し、post_id、meta_key、meta_valueによるインデックスを作成することです。これはインデックスを使うことでクエリを高速化するでしょうが、おそらくそれほど速くはありません。
しかし、以前のものよりも実装がはるかに簡単なので、私はおそらく最初にこの2番目のオプションを実装し、それがどのようになるかを見ることを試みるでしょう。
1日あたりの変更量がそれほど大きくないと仮定すると、照会に適した形式で "シャドウDB"を作成できます。たとえば、各属性に独自の列があり、保存後に毎回更新します。
このアプローチの利点は、post/meta/termsの使用法、adminの変更、およびフロントエンドの変更を何も変更する必要がないことです。データを調整するためにコードを記述する必要があるという欠点があります。すべての投稿と一時保存はコードを書く際に、そしてそれぞれの更新でDBサーバーにいくらかあなたのためにもう少しの仕事を作成するでしょう。