歲月留聲

WordPress 百万级优化 SQL_CALC_FOUND_ROWS 数据库慢查询解决方案

WordPress 在查询 post 列表时,默认会同时把文章数量也查询出来,使用这种方式的有:get_posts、query_posts 和 WP_Query。

「WordPress 百万级优化 SQL_CALC_FOUND_ROWS 数据库慢查询解决方案:https://0xo.net/1998」

WordPress 百万级优化 SQL_CALC_FOUND_ROWS 数据库慢查询解决方案 - 第1张图片

SQL_CALC_FOUND_ROWS 简介

SQL_CALC_FOUND_ROWS 是一个早期 MySql 函数,用于返回一个数据库查询的总行数,以便计算分页所需的页数。问题是,SQL_CALC_FOUND_ROWS 是一个相当古老的函数,没有优化,效率特别低,会拖慢数据库查询。

get_posts 在 WordPress 4.6.1+ 已经不再使用 SQL_CALC_FOUND_ROWS,但是 query_posts 和 WP_Query 还是会用,所以文章数目比较多的话还须优化。

「WordPress 百万级优化 SQL_CALC_FOUND_ROWS 数据库慢查询解决方案:https://0xo.net/1998」

具体语句如下:

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
SELECT FOUND_ROWS()

一般在 WordPress 博客网站文章数据量较小时,基本没问题。但是当文章 posts 数量达到 10w+,这个就是一条必现的慢查询,有时候上千文章数量也会偶尔出现。比如首页、分类、标签、搜索页面,只要用到这几个函数,就都会使用 SQL_CALC_FOUND_ROWS。

如何解决 SQL_CALC_FOUND_ROWS 问题优化 WordPress 速度?

禁用掉 SQL_CALC_FOUND_ROWS,用一种更加高效的方式,参考代码如下:

「WordPress 百万级优化 SQL_CALC_FOUND_ROWS 数据库慢查询解决方案:https://0xo.net/1998」
//优化数据库慢查询 uxtt.com
if ( ! function_exists( 'theme_set_no_found_rows' ) ){
/**
* 设置 'no_found_rows' 属性为 true,禁用 SQL_CALC_FOUND_ROWS
*/
function theme_set_no_found_rows( \WP_Query $wp_query ) {
$wp_query->set( 'no_found_rows', true );
}
}
add_filter( 'pre_get_posts', 'theme_set_no_found_rows', 10, 1 );

if ( ! function_exists( 'theme_set_found_posts' ) ){
//构建和设置分页
function theme_set_found_posts( $clauses, \WP_Query $wp_query ) {
//单页不处理 uxtt.com
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 );

return $clauses;
}
}
add_filter( 'posts_clauses', 'theme_set_found_posts', 10, 2 );

代码复制粘贴到主题 functions.php 文件保存生效即可。有需要不妨试试。

参考资料

WordPress 10w+数据时, 解决 SQL_CALC_FOUND_ROWS 查询使网站变慢问题(文章代码可能导致分页不准确)

解决 SQL_CALC_FOUND_ROWS 数据库慢查询问题的解决方案

「WordPress 百万级优化 SQL_CALC_FOUND_ROWS 数据库慢查询解决方案:https://0xo.net/1998」

WordPress: SQL_CALC_FOUND_ROWS, why it’s slow and what to do about it

退出移动版