一个实际的例子,给大家演示一下如何发现 WordPress 性能卡点以及我怎么优化的!
对于程序员来说,找到问题比解决问题更重要,WordPress 性能优化也是一样,重点也是找到性能的卡点,WordPress 和其他 PHP 程序一样,最大的卡点就是数据库请求,慢 SQL 请求或者大量 SQL 请求往往就是性能最大的卡点。
Log 定位系统
「WordPress 文章超过10万就会负载很高,是不是不适合做大网站?」这篇文章中我就提到我是自己开发的一插件,将慢查询或者同时大量 SQL 查询记录下来:

上图就是 Autumn Pro 主题的后台检测结果,举个例子,打开其中一个文件:

原来是 Automn-Pro 主题的标签汇云页面:

该标签云页面现实热门的标签,然后每个标签并且也显示最新的一篇文章,查看实现的源代码:
if($tags = get_tags('orderby=count&order=DESC&number=28')){
foreach($tags as $tag){
echo '<li><a class="name" href="'.get_tag_link($tag).'">'. $tag->name .'</a><small>x '. $tag->count .'</small><br>';
foreach(get_posts( "tag_id=". $tag->term_id ."&numberposts=1") as $post) {
echo '<p><a class="tit" href="'.get_permalink($post).'">'.get_the_title($post).'</a></p>';
}
echo '</li>';
}
}
这些热门标签下的最新文章的获取,每一个都是独立通过 WP_Query 获取,在有缓存的情况下:

如果缓存都失效,也就是缓存塌陷的情况下,就是会有 28 个 WP_Query 的缓存都失效:

整整有 100 多条 SQL,虽然耗时都差不多,但是如果这样的情况很多,访问量一大,那么 MySQL 请求资源池就会被耗尽。
修改代码优化性能
发现了问题,优化就很简单了,就不能用每个标签去都使用一个 WP_Query获取,使用 tag__in 参数一起获取,但是文章使用标签的可能会连续,我们把获取的文章数量放大一些,并且改成 while 操作,直到所有标签都有了相应的文章:
$tag_ids = array_column(get_tags('orderby=count&order=DESC&number=28'), 'term_id');
$tag_posts = array_fill_keys($tag_ids, null);
while($tag_ids){
foreach(get_posts(['tag__in'=>$tag_ids, 'posts_per_page'=>count($tag_ids)*5]) as $post){
foreach(get_the_tags($post) as $tag){
$tag_id = $tag->term_id;
if(!isset($tag_posts[$tag_id]) && in_array($tag_id, $tag_ids)){
$tag_ids = array_diff($tag_ids, [$tag_id]);
$tag_posts[$tag_id] = [$tag, $post];
}
}
if(!$tag_ids){
break;
}
}
}
foreach($tag_posts as [$tag, $post]){
echo '<li><a class="name" href="'.get_tag_link($tag).'">'. $tag->name .'</a><small>x '. $tag->count .'</small><br>';
echo '<p><a class="tit" href="'.get_permalink($post).'">'.get_the_title($post).'</a></p>';
echo '</li>';
}
这样最佳的情况只要一个 WP_Query 就能解决问题,我上面放到了 5 倍的数量,最差 2-3 个 WP_Query 也就基本查到所有热门标签对应的文章。
当然我们的 WordPress Jam 也提供 WordPress 性能优化外包服务,只要你的服务器有 root 权限,请直接联系我的 denis@wpjam.com,或者加我的微信:chenduopapa。
