当前位置: 首页>>网站问题>>正文


获得postmeta帖子的最有效方式

webfans 网站问题 , , 去评论

问题描述

我需要获得一堆带有元数据的帖子。当然,您无法使用标准帖子查询获取元数据,因此您通常必须为每个帖子执行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表连接?我可以在一个查询中获取所有发布数据,然后在另一个查询中获取所有相关的postmeta,并将meta与发布数据合并到PHP中的一个结果集中。最终会比单个ever-more-complex SQL查询更快,如果可能的话?

我一直认为,“尽可能多地为数据库工作。”不确定这一个!

最佳解决方法

发布元信息会自动缓存在内存中,用于标准WP_Query(和主查询),除非您明确告诉它不要使用update_post_meta_cache参数。

因此,您不应该为此编写自己的查询。

元缓存如何适用于普通查询:

如果WP_Queryupdate_post_meta_cache参数未设置为false,则在从DB检索到帖子后,将调用update_post_caches()函数,该函数又调用update_postmeta_cache()

update_postmeta_cache()功能是update_meta_cache()的包装,它本质上与调用检索到的帖子的所有ID是一个简单的SELECT。这将获得查询中所有帖子的所有postmeta,并将该数据保存在对象缓存中(使用wp_cache_add())。

当您执行类似get_post_custom()的操作时,它会首先检查该对象缓存。所以现在没有额外的查询来获得post meta。如果您已经在WP_Query中获得了帖子,那么元已经在内存中并且从那里直接得到它。

这里的优点比进行复杂查询要多很多倍,但最大的优势来自于使用对象缓存。如果您使用持久性内存缓存解决方案(如XCache或memcached或APC等),并且有一个可以将对象缓存绑定到它的插件(例如W3 Total Cache),那么整个对象缓存将存储在快速内存中已经。在这种情况下,检索数据所需的查询次数为零;它已经在 memory 中了。持久对象缓存在很多方面都很棒。

换句话说,您的查询可能比使用正确的查询和简单的持久内存解决方案更慢地加载和加载。使用普通的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('||',$a->meta_keys),array_map('maybe_unserialize',explode('||',$a->meta_values)));
    unset($a->meta_keys);
    unset($a->meta_values);
    return $a;
}

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

这平均花费0.7秒。这大约是WP get_post_custom()解决方案的四分之一时间和大约一半的数据透视查询解决方案。

也许这会让某些人感兴趣。

第四种方法

我发现自己处于一种情况,我需要完成这项任务才能最终创建一个CSV文档,我最终直接使用mysql来完成这项工作。我的代码加入post和meta表来检索woocommerce定价信息,之前发布的解决方案要求我在sql中使用表别名才能正常工作。

SELECT p.ID, p.post_title, 
    MAX(CASE WHEN pm1.meta_key = '_price' then pm1.meta_value ELSE NULL END) as price,
    MAX(CASE WHEN pm1.meta_key = '_regular_price' then pm1.meta_value ELSE NULL END) as regular_price,
    MAX(CASE WHEN pm1.meta_key = '_sale_price' then pm1.meta_value ELSE NULL END) as sale_price,
    MAX(CASE WHEN pm1.meta_key = '_sku' then pm1.meta_value ELSE NULL END) as sku
    FROM wp_posts p LEFT JOIN wp_postmeta pm1 ON ( pm1.post_id = p.ID)                 
    WHERE p.post_type in('product', 'product_variation') AND p.post_status = 'publish'
    GROUP BY p.ID, p.post_title

请注意,woocommerce在我的元表中创建了300K +行,所以它非常大,因此非常慢。

参考资料

本文由朵颐IT整理自网络, 文章地址: https://duoyit.com/article/3016.html,转载请务必附带本地址声明。