Wordpress列表页加载缓慢优化参数SQL_CALC_FOUND_ROWS 查询,实现提速分页功能

WordPress在查询post列表时,默认会同时把文章数量也查询出来,会使用到例如以边语句格式:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' ) ORDER BY wp_posts.post_date DESC LIMIT 0, 20
SQL_CALC_FOUND_ROWS MySQL 是一个慢查询,被 WordPress 用来在分页程序中获取查询结果总数量,这个查询的速度非常慢,加上 WordPress 不能缓存这个查询结果,当文章数量比较多的时候WordPress 的列表页打开速度会。

使用这种方式的有:get_posts 、query_posts和WP_Query。

get_posts在4.6.1+已经不用SQL_CALC_FOUND_ROWS,但是query_posts和WP_Query还是会用,所以还须优化。

但是当post数量到10w+的时候,这个就是一条必现的慢查询,

首页、分类、标签、搜索页面,只要用到这几个函数,就都会使用SQL_CALC_FOUND_ROWS这个方式。

解决方法:

禁用掉SQL_CALC_FOUND_ROWS用法,用一种更加高效的方式,

这里我们用EXPLAIN方式,为什么用EXPLAIN而不是count(*)?

注:为了实现分页功能,WordPress 在很多查询中都使用了 SQL_CALC_FOUND_ROWS MySQL 查询,即使我们根本不需要分页功能,SQL_CALC_FOUND_ROWS 的功能是让 MySQL 计算在数据库中总共有多少条记录匹配查询的条件,如果匹配的记录非常多,这将是非常耗费时间的一件事情。

一、设置 no_found_rows 禁止 SQL_CALC_FOUND_ROWS 查询

通过查看 WordPress 3.x 的源码,我发现了一个没有写在参考文档里面参数:no_found_rows ,这个参数接受的值为布尔值,它可以告诉 query_posts 和 WP_Query 不要计算总匹配数量,我们可以这样使用:
query_posts('no_found_rows=true&cat=1&numberposts=1');
这样,WordPress 再查询文章的时候,就不会再进行不必要的总匹配记录数计算了,对提高 WordPress 页面速度和节能环保多多少少会有一点帮助。

二、使用 COUNT(*) 代替 SQL_CALC_FOUND_ROWS

除了 SQL_CALC_FOUND_ROWS 查询,在 MySQL 中我们还可以使用 COUNT(*) 来获取总行数,经过对比,我们发现后者的速度比前者要快不少(有时候会快到 10 倍之多),我们可以使用 COUNT(*) 来代替 SQL_CALC_FOUND_ROWS 查询来获取总行数,这样既可以加快查询速度,又不会损失分页功能。

首先,我们使用 pre_get_posts Filter 钩子,直接在所有查询中设置 no_found_rows 禁用 SQL_CALC_FOUND_ROWS 查询。
add_filter('pre_get_posts', function (\WP_Query $wp_query)
{
$wp_query->set('no_found_rows', true);
});
添加了以上代码,所有 WordPress 查询中的分页参数便缺失了,分页功能自然就失效了。我们需要使用 posts_clauses 钩子修改 WordPress 数据库查询,使用 COUNT(*) 查询来获取总行数,并设置分页所需要的参数。
add_filter('posts_clauses', function ($clauses, \WP_Query $wp_query)
{
// 跳过单页面
if ($wp_query->is_singular()) {
return $clauses;
}

global $wpdb;

// 查询是否设置了一下变量
$where = isset($clauses[ 'where' ]) ? $clauses[ 'where' ] : '';
$join = isset($clauses[ 'join' ]) ? $clauses[ 'join' ] : '';
$distinct = isset($clauses[ 'distinct' ]) ? $clauses[ 'distinct' ] : '';

// 构造并运行查询,将查询结果设置为我们要运行主查询的 “found_posts” 参数。
$wp_query->found_posts = $wpdb->get_var("SELECT $distinct COUNT(*) FROM {$wpdb->posts} $join WHERE 1=1 $where");

// 计算每页应该有多少文章。
$posts_per_page = (! empty($wp_query->query_vars[ 'posts_per_page' ]) ? absint($wp_query->query_vars[ 'posts_per_page' ]) : absint(get_option('posts_per_page')));

// 设置 max_num_pages 参数
$wp_query->max_num_pages = ceil($wp_query->found_posts / $posts_per_page);

// 返回 $clauses 自查询,以便运行主查询
return $clauses;
}, 10, 2);
添加了以上代码之后,我们便把使用 COUNT(*) 查询替换 SQL_CALC_FOUND_ROWS 查询,如果您的 WordPress 文章总数比较多 (千条以上),查询加速的变化会非常明显。

#现在前往

精选留言

Wordpress,FOUND,分页,提速
sample
2021-03-23
写留言
签到
投稿
QQ咨询
返回顶部