問題描述

我需要得到一堆他們的後設資料的帖子。當然,您無法使用標準的帖子查詢獲取後設資料,因此您通常必須為每個帖子執行 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。