自定义帖子类型的慢WP_QUERY

时间:2016-09-14 作者:Johnny

我有一个定制贴子:属性的房地产主题。Post有许多元值,如价格和分类法,如位置。我为此创建了搜索引擎,但查询需要花费大量的时间来执行。

我在数据库中只有50个属性,但wp\\U Posteta表有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\\u查询的$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
我已经阅读了许多相关的问题,但找不到任何描述hot to change查询的答案。

谢谢

EDIT:

我创建了自定义SQL,它似乎以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
现在,我将尝试将所有meta\\u查询(导致性能问题)添加为自定义SQLadd_filter( \'posts_where\' , \'posts_where_statement\' );

2 个回复
SO网友:Xavi Ivars

这是WordPress和涉及Posteta的搜索的一个已知问题。

我将尝试为您通常搜索最多的“事物”创建一个新的分类法:

  • offer_order_status 似乎是更好的候选人,因为它可以是积极的或不积极的。我将创建一个包含两个元素的分类法。这将大大减少您的搜索时间。如果这还不够,我可能会尝试的下一步是为您使用的其他两个“元”定义“桶”,并为它们创建分类:面积和价格。Bucket可以以不同的方式创建:您可以有一个“大小”分类法> 100000, 另一个> 200000, 等等,然后对于价格,您可能想< 100000, > 100000 && < 200000. 这实际上取决于您计划如何搜索
第二步的要点是,您可以挂接到帖子的保存操作,以“读取”该属性的面积/大小,然后为其选择正确的分类法,并在后端自动添加它们。这样做的好处是:a)使分类法始终与实际的元值同步(你不想让人们多次添加“相同”或类似的信息)。b) 您可以随时更改分类法的“bucket”,以满足您的“新”需求:由于这些字段具有真正的价值,您只需再次“保存”所有帖子即可获得正确的分类法(您可以通过编程实现)。c) 基于分类法的搜索比元搜索快得多(与Posteta相比,它是一个索引表&相对较小的表)

第二种方法虽然在这种情况下效果不太好,但仍然是一种选择,即向postETA表添加索引,通过post\\u id、meta\\u key和meta\\u value进行索引。通过使用索引,这也会加快查询速度,但可能不会太快。

但由于它比前一个更容易实现,我可能会先尝试实现第二个选项,看看它是如何实现的。

SO网友:Mark Kaplun

假设每天的更改量不大,您可以创建一个更便于查询的“shadow DB”,例如每个属性都有自己的列,并在每次保存后更新它。

这种方法的优点是,您不必更改post/meta/terms用法中的任何内容,也不必更改admin,前端也不必更改。缺点是,您确实需要编写代码来调整每次post和tem保存时的数据,这将为您编写代码和每次更新时的DB服务器创建更多的工作。