WordPress中get_post_status批量查询过慢,求高效校验文章发布状态的方案
核心问题说明
你之前的两种方案性能差的核心原因是循环内单次查询数据库,2万条数据对应2万次数据库请求,IO开销累加导致耗时居高不下,这完全是可以避免的。你之前测试自定义SQL没有提升耗时,只是因为你没有减少查询次数,仅降低了WP内核加载Post对象的内存开销而已。
最优性能优化方案
核心思路是把多次查询合并为1次批量查询,减少数据库交互次数:
- 先从原数组中提取所有需要校验的leadID,先做去重处理减少不必要的查询
- 用SQL的IN语法一次性查询所有符合「ID在目标列表、状态为publish」的文章ID,存为查找表
- 遍历原数组时直接从查找表判断状态,无需再查询数据库
实现代码
// 第一步:提取所有需要校验的leadID并去重,同时提前处理业务字段 $allLeadIds = []; $validItems = []; foreach($superUserLeads as $data){ $leadid = intval($data["leadID"]); if($leadid > 0){ $allLeadIds[] = $leadid; } // 提前处理shopMailSended字段,不用等待数据库查询结果 $shopMailSended = isset($data["EK_WKDM_shop_mail_bike_not_sold_1"]) ? filter_var($data["EK_WKDM_shop_mail_bike_not_sold_1"], FILTER_VALIDATE_BOOLEAN) : false; $validItems[$leadid] = $shopMailSended; } $allLeadIds = array_unique($allLeadIds); // 第二步:批量查询所有已发布的leadID,仅1次数据库请求 global $wpdb; $publishedIds = []; if(!empty($allLeadIds)){ // 用wpdb的prepare方法防止SQL注入 $idsPlaceholders = implode(',', array_fill(0, count($allLeadIds), '%d')); $sql = $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE ID IN ($idsPlaceholders) AND post_status = 'publish'", $allLeadIds ); $publishedIds = $wpdb->get_col($sql); // 转成键名为ID的数组,后续查找时间复杂度为O(1) $publishedIds = array_flip($publishedIds); } // 第三步:遍历统计符合条件的数量,无额外数据库请求 $bikeEach = 0; foreach($validItems as $leadid => $shopMailSended){ if($shopMailSended && isset($publishedIds[$leadid])){ $bikeEach++; // 其他业务逻辑 } }
优化效果
这套方案仅需要1次数据库查询,不管是2万条还是更多数据,耗时基本都能控制在数百毫秒级别,远低于之前的15秒。如果这个逻辑是高频触发的,还可以把查询到的已发布ID列表用WordPress的transient机制缓存一段时间(比如5分钟),进一步降低数据库压力。
内容的提问来源于stack exchange,提问作者enky
相关产品推荐
相关产品推荐

