2012-10-24 42 views
1

我會在優化這個WordPress查詢一些幫助,但目前需要100%的CPU使用率,從來沒有得到機會它完成:需要優化的wordpress meta_query

SELECT wp_posts.* FROM wp_posts 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) 
INNER JOIN wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id) 
INNER JOIN wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id) 
INNER JOIN wp_postmeta AS mt6 ON (wp_posts.ID = mt6.post_id) 
INNER JOIN wp_postmeta AS mt7 ON (wp_posts.ID = mt7.post_id) 
INNER JOIN wp_postmeta AS mt8 ON (wp_posts.ID = mt8.post_id) 
INNER JOIN wp_postmeta AS mt9 ON (wp_posts.ID = mt9.post_id) 
INNER JOIN wp_postmeta AS mt10 ON (wp_posts.ID = mt10.post_id) WHERE 1=1 AND wp_posts.post_type = 'produkter' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') AND (wp_postmeta.meta_key = 'csv_product_month_sub' 
OR (mt1.meta_key = 'csv_product_type' AND CAST(mt1.meta_value AS CHAR) = 'Mobilt Bredbaand') 
OR (mt2.meta_key = 'csv_product_consumption' AND CAST(mt2.meta_value AS SIGNED) BETWEEN '0' AND '2') 
OR (mt3.meta_key = 'csv_product_consumption' AND CAST(mt3.meta_value AS SIGNED) BETWEEN '3' AND '9') 
OR (mt4.meta_key = 'csv_product_consumption' AND CAST(mt4.meta_value AS SIGNED) BETWEEN '10' AND '19') 
OR (mt5.meta_key = 'csv_product_download' AND CAST(mt5.meta_value AS SIGNED) BETWEEN '2' AND '9') 
OR (mt6.meta_key = 'csv_product_download' AND CAST(mt6.meta_value AS SIGNED) BETWEEN '10' AND '19') 
OR (mt7.meta_key = 'csv_product_download' AND CAST(mt7.meta_value AS SIGNED) BETWEEN '20' AND '29') 
OR (mt8.meta_key = 'csv_product_month_sub' AND CAST(mt8.meta_value AS SIGNED) BETWEEN '0' AND '49') 
OR (mt9.meta_key = 'csv_product_month_sub' AND CAST(mt9.meta_value AS SIGNED) BETWEEN '50' AND '99') 
OR (mt10.meta_key = 'csv_product_month_sub' AND CAST(mt10.meta_value AS SIGNED) BETWEEN '100' AND '149')) GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value+0 ASC 
+0

首先你爲什麼使用INNER JOINs? 那是什麼ORDER meta_value + 0? 爲什麼你爲同一個meta_key檢查做3個OR? – Svetoslav

+0

該查詢由WP_Query生成。每個meta_key有3個ORS,因爲它會在每個元素中檢查不同的範圍/值。 –

+0

我認爲給ORDER BY加上+0,它會「強制」mysql使用該值作爲數字,而不是文本。 –

回答

0

到目前爲止,我有:

SELECT wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) 
WHERE ID IN (
      SELECT post_id from wp_postmeta 
      WHERE 
      (
       (meta_key = 'csv_product_consumption' AND CAST(meta_value AS SIGNED) BETWEEN 0 AND 2) 
       OR (meta_key = 'csv_product_consumption' AND CAST(meta_value AS SIGNED) BETWEEN 3 AND 9) 
       OR (meta_key = 'csv_product_consumption' AND CAST(meta_value AS SIGNED) BETWEEN 10 AND 19) 
       OR (meta_key = 'csv_product_download' AND CAST(meta_value AS SIGNED) BETWEEN 2 AND 9) 
       OR (meta_key = 'csv_product_download' AND CAST(meta_value AS SIGNED) BETWEEN 10 AND 19) 
       OR (meta_key = 'csv_product_download' AND CAST(meta_value AS SIGNED) BETWEEN 20 AND 29) 
       OR (meta_key = 'csv_product_month_sub' AND CAST(meta_value AS SIGNED) BETWEEN 0 AND 49) 
       OR (meta_key = 'csv_product_month_sub' AND CAST(meta_value AS SIGNED) BETWEEN 50 AND 99) 
       OR (meta_key = 'csv_product_month_sub' AND CAST(meta_value AS SIGNED) BETWEEN 100 AND 149) 
      ) 
      GROUP BY post_id 
     ) 
AND wp_posts.post_type = 'produkter' 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') 
AND ((wp_postmeta.meta_key = 'csv_product_type') AND (wp_postmeta.meta_value = 'Mobilt Bredbaand')) 
ORDER BY wp_postmeta.meta_value+0 ASC 

它不再使用太多的CPU,查詢需要0.0331秒。

任何其他的想法,將不勝感激。

0

我遇到了這個問題,並意識到問題是所有由WordPress生成的INNER JOINS。我得到了WordPress的原始查詢:

SELECT wp_posts.* 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) 
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) 
INNER JOIN wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id) 
INNER JOIN wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id) WHERE 1=1 AND (wp_term_relationships.term_taxonomy_id IN (7,11,12,13,14,15) AND wp_posts.ID NOT IN (
        SELECT object_id 
        FROM wp_term_relationships 
        WHERE term_taxonomy_id IN (10) 
       )) AND wp_posts.post_type IN ('post', 'page', 'attachment', 'product', 'store_page') AND (wp_posts.post_status = 'publish') AND ((wp_postmeta.meta_key = 'product_type' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt1.meta_key = 'product_type2' AND CAST(mt1.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt2.meta_key = 'product_type3' AND CAST(mt2.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt3.meta_key = 'product_type4' AND CAST(mt3.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt4.meta_key = 'product_type5' AND CAST(mt4.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt5.meta_key = 'product_type6' AND CAST(mt5.meta_value AS CHAR) = 'type_pre_ground')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC 

這從來沒有完成,並在非常高的負載捆綁CPU。我刪除了過去兩年內連接(以及相應的WHERE子句),並得到了2秒的成績:

SELECT wp_posts.* 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) 
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 (7,11,12,13,14,15) AND wp_posts.ID NOT IN (
        SELECT object_id 
        FROM wp_term_relationships 
        WHERE term_taxonomy_id IN (10) 
       )) AND wp_posts.post_type IN ('post', 'page', 'attachment', 'product', 'store_page') AND (wp_posts.post_status = 'publish') AND ((wp_postmeta.meta_key = 'product_type' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt1.meta_key = 'product_type2' AND CAST(mt1.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt2.meta_key = 'product_type3' AND CAST(mt2.meta_value AS CHAR) = 'type_pre_ground') 
OR (mt3.meta_key = 'product_type4' AND CAST(mt3.meta_value AS CHAR) = 'type_pre_ground')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC 

所以我意識到,去除內連接的關鍵是加快查詢。我重新寫了查詢,只有一個wp_postmeta INNER JOIN和在幾分之一秒內得到結果:

SELECT wp_posts.* 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) WHERE 1=1 AND (wp_term_relationships.term_taxonomy_id IN (7,11,12,13,14,15) AND wp_posts.ID NOT IN (
        SELECT object_id 
        FROM wp_term_relationships 
        WHERE term_taxonomy_id IN (10) 
       )) 
AND wp_posts.post_type IN ('post', 'page', 'attachment', 'product', 'store_page') 
AND (wp_posts.post_status = 'publish') 
AND ((wp_postmeta.meta_key = 'product_type' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') 
OR (wp_postmeta.meta_key = 'product_type2' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') 
OR (wp_postmeta.meta_key = 'product_type3' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') 
OR (wp_postmeta.meta_key = 'product_type4' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') 
OR (wp_postmeta.meta_key = 'product_type5' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') 
OR (wp_postmeta.meta_key = 'product_type6' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')) 
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC 

有了這個解決方案,我創建了一個WordPress的過濾器的postmeta查詢轉換爲更快的格式:

function custom_get_meta_sql($meta_sql) 
{ 
    global $wpdb; 

    $posts_table = $wpdb->prefix . 'posts'; 
    $postmeta_table = $wpdb->prefix . 'postmeta'; 

    //use single INNER JOIN 
    $meta_sql['join'] = " INNER JOIN {$postmeta_table} AS pmta ON ({$posts_table}.ID = pmta.post_id) "; 

    //replace the mtNN aliases with wp_postmeta 
    $where_clause = $meta_sql['where']; 
    $where_clause = str_replace("{$postmeta_table}.", 'pmta.', $where_clause); 
    $where_clause = preg_replace('/mt\d+\.meta_/i', 'pmta.meta_', $where_clause); 

    $meta_sql['where'] = $where_clause; 
    return $meta_sql; 
} 

add_filter('get_meta_sql', 'custom_get_meta_sql'); 

此過濾器應位於WordPress主題的functions.php文件中。

+0

感謝分享此。也許我錯過了一些東西,但我不明白這是如何工作的。 WordPress是否創建了多個INNER JOINS來允許SQL在同一個查詢中選擇不同的meta_keys和meta_values?我不是SQL專家,但看看結果,好像WHERE子句由AND連接,這種類型的查詢將始終返回0結果。這是因爲在第一種情況下,我們檢查'pmta.meta_key =「x」',在第二種情況下我們檢查'ptma.meta_key =「y」'。兩者都不對,對嗎?我真的很想在這方面做錯。我錯過了什麼? –

+0

由於對內部AND的結果執行AND,因此該查詢將工作:(KEY_CONDITION1 AND VALUE_CONDITION1)AND(KEY_CONDITION2 AND VALUE_CONDITION2)。 KEY_CONDITION1不必與KEY_CONDITION2一致,因爲它正在針對相應的VALUE_CONDITION1進行測試。在你的例子中,KEY_CONDITION1是'pmta.meta_key =「x」'。您還需要具有VALUE_CONDITION1才能複製查詢正在測試的內容。 – KalenGi

+0

我不明白爲什麼我會得到0結果。我用正在生成的SQL打開了一個新問題。想看看? HTTP://計算器。com/q/15439474/931860 –

0

這是一箇舊的帖子,但你可以考慮嘗試Horizo​​ntal Meta。水平元監視用戶元表中的後&中的特定鍵,並將它們提取爲關係/水平格式。您仍然可以使用WordPress查詢引擎來運行查詢,但是水平元將會重寫查詢來加速查詢。 Available here:http://wordpress.org/plugins/horizontal-meta/

+0

非常有趣。謝謝! –