問題描述

我需要得到一堆他們的元數據的帖子。當然,您無法使用標準的帖子查詢獲取元數據,因此您通常必須為每個帖子執行 get_post_custom()

我正在嘗試使用一個自定義查詢,如下所示:

$results = $wpdb->get_results("
    SELECT  p.ID,
        p.post_title,
        pm1.meta_value AS first_field,
        pm2.meta_value AS second_field,
        pm3.meta_value AS third_field
    FROM    $wpdb->posts p LEFT JOIN $wpdb->postmeta pm1 ON (
            pm1.post_id = p.ID  AND
            pm1.meta_key    = 'first_field_key'
        ) LEFT JOIN $wpdb->postmeta pm2 ON (
            pm2.post_id = p.ID  AND
            pm2.meta_key    = 'second_field_key'
        ) LEFT JOIN $wpdb->postmeta pm3 ON (
            pm3.post_id = p.ID  AND
            pm3.meta_key    = 'third_field_key'
        )
    WHERE   post_status = 'publish'
");

似乎工作如果您使用任何這些元字段,可以在同一個文章中允許其多個元值的方式,那麼它會跳過。我不能想到一個加入來做到這一點。

那麼,問題 1:有沒有加入,sub-query 或什麼,帶入 multiple-value 元字段?

但問題 2:值得嗎?在添加 2 查詢方法之前,需要添加多少個 postmeta 表連接?我可以在一個查詢中抓取所有的帖子數據,然後在另一個查詢中獲取所有相關的後期數據,並將元數據與 PHP 中的一個結果集中的後期數據相結合。最終會比單個 ever-more-complex SQL 查詢更快嗎?

我一直認為,「儘可能多地向數據庫工作。」 不確定這個!

最佳解決方案

發佈元信息自動緩存在內存中用於標準 WP_Query(和主查詢),除非您明確告知不使用 update_post_meta_cache 參數。

因此,您不應該為此編寫自己的查詢。

元緩存如何適用於普通查詢:

如果 WP_Query 的 update_post_meta_cache 參數未設置為 false,則在從 DB 中檢索到帖子後,將調用 update_post_caches() 函數,然後調用 update_postmeta_cache() 。

update_postmeta_cache()功能是 update_meta_cache()的封裝,它本質上調用了一個簡單的 SELECT,其中檢索到所有帖子的 ID 。這將獲得查詢中所有帖子的所有 postmeta,並將該數據保存在對象緩存中 (使用 wp_cache_add()) 。

當你做一些像 get_post_custom()這樣的事情,它首先檢查對象緩存。所以在這一點上沒有額外的查詢來獲取帖子元數據。如果你已經在 WP_Query 中找到了這個帖子,那麼這個元數據已經在內存裏了,直接從那裏得到。

這裏的優點比複雜的查詢大很多倍,但最大的優點在於使用對象緩存。如果您使用像 XCache 或 memcached 或 APC 這樣的持久性內存緩存解決方案,並且具有可以將對象緩存綁定到其上的插件 (例如,W3 Total Cache),則整個對象緩存將被存儲在快速內存中已經。在這種情況下,檢索您的數據需要零查詢; 它已經在記憶中了持久性對象緩存在許多方面都非常棒。

換句話説,您的查詢可能會比使用正確的查詢和簡單的持久內存解決方案加載和加載更慢。使用正常的 WP_Query 。節省一些努力。

附加:update_meta_cache()是智能的,BTW 。它不會為已經有其元信息緩存的帖子檢索元信息。基本上沒有得到相同的兩次元。超高效。

額外的附加:「儘可能多的工作到數據庫。」… 不,這是網絡。不同規則適用。一般來説,如果可行,您總是希望儘可能少地向數據庫提供任何工作。數據庫緩慢或配置不佳 (如果您沒有具體配置,您可以賭錢,這是真的) 。通常它們在許多站點之間共享,並在一定程度上超載。通常你有比數據庫更多的 Web 服務器。一般來説,您只需要儘可能快速地將數據從數據庫中獲取,然後使用 web-server-side 代碼進行排序。作為一般原則,當然不同的情況都是不同的。

次佳解決方案

我會推薦一個樞軸查詢。使用你的例子:

SELECT  p.ID,
        p.post_title,
        MAX(CASE WHEN wp_postmeta.meta_key = 'first_field' then wp_postmeta.meta_value ELSE NULL END) as first_field,
        MAX(CASE WHEN wp_postmeta.meta_key = 'second_field' then wp_postmeta.meta_value ELSE NULL END) as second_field,
        MAX(CASE WHEN wp_postmeta.meta_key = 'third_field' then wp_postmeta.meta_value ELSE NULL END) as third_field,

 FROM    wp_posts p LEFT JOIN wp_postmeta pm1 ON ( pm1.post_id = p.ID)
GROUP BY
   wp_posts.ID,wp_posts.post_title

第三種解決方案

我遇到一個案例,我想也想快速檢索大量的帖子與他們相關聯的元信息。我需要檢索 O(2000) 的帖子。

我嘗試使用 Otto 的建議 – 為所有帖子運行 WP_Query :: query,然後為每個帖子循環並運行 get_post_custom 。平均來説,這需要約 3 秒才能完成。

然後我嘗試了 Ethan 的透視查詢 (雖然我不喜歡手動請求我感興趣的每個 meta_key) 。我仍然不得不循環通過所有檢索的帖子來取消串行化 meta_value 。平均來説,這需要大約 1.3 秒才能完成。

然後我嘗試使用 GROUP_CONCAT 功能,並找到最好的結果。以下是代碼:

global $wpdb;
$wpdb->query('SET SESSION group_concat_max_len = 10000'); // necessary to get more than 1024 characters in the GROUP_CONCAT columns below
$query = "
    SELECT p.*,
    GROUP_CONCAT(pm.meta_key ORDER BY pm.meta_key DESC SEPARATOR '||') as meta_keys,
    GROUP_CONCAT(pm.meta_value ORDER BY pm.meta_key DESC SEPARATOR '||') as meta_values
    FROM $wpdb->posts p
    LEFT JOIN $wpdb->postmeta pm on pm.post_id = p.ID
    WHERE p.post_type = 'product' and p.post_status = 'publish'
    GROUP BY p.ID
";

$products = $wpdb->get_results($query);

// massages the products to have a member ->meta with the unserialized values as expected
function massage($a){
    $a->meta = array_combine(explode('||',$product->meta_keys),array_map('maybe_unserialize',explode('||',$product->meta_values)));
    unset($a->meta_keys);
    unset($a->meta_values);
}

$products = array_map('massage',$products);

平均 0.7 秒。這是 WP get_post_custom() 解決方案大約四分之一的時間和大約一半的數據查詢解決方案。

也許這對某人有興趣。

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。