WordPress 6.8 提升了 WordPress 的查询效率!

WordPress 6.8 通过对参数标准化操作,来保证生成缓存的键名(cache key)的一致,提高具有等效参数的查询的缓存命中率,最终实现 WP_Query 缓存效率的提升。

参数标准化

开始之前,我们先了解一下什么是参数标准化?

举个 WP_Query 最常见的使用场景,就是查询多个文章类型时,我们可以会有下面三种写法:

$q1 = new WP_Query(['post_type' => ['post', 'page']]);
$q2 = new WP_Query(['post_type' => ['page', 'post']]);
$q3 = new WP_Query(['post_type' => ['page', 'post', 'post']]);

其实这三个查询的结果其实是一样的,但是在 WordPress 6.7 及之前的例子,因为 WordPress 生成缓存键名之前,没有进行去重和排序等操作,造成了生成的 key 不同,每次查询都会去数据中获取。而在 6.8 中,post_type 参数会按字母排序并去重,我们可以通过 get 方法获取一下看 post_type 的值:

$q1->get('post_type'); // 返回 ['page', 'post']
$q2->get('post_type'); // 返回 ['page', 'post']
$q3->get('post_type'); // 返回 ['page', 'post']

这样,这三个查询在第一次使用的时候,只有第一个会去数据库中去查询,第二个和第三个则直接从缓存中获取。

对于接受整数或字符串的参数(如 author__not_in),则进行类型转换和排序来实现参数标准化,author__not_in => ['2', '1'] 会转换为 author__not_in => [1, 2]

另外如果 WP_Query 的参数以字符串形式传递,则不会转换为数组:

$q4 = new WP_Query(['post_type' => 'post']);
$q4->get('post_type'); // 返回 'post'

开发者的问题

这样修改,可能会对插件和主题开发者造成一定兼容的问题,可能会影响使用 WP_Query::get() 方法和 WP_Query::$query_vars 属性的主题和插件,尤其是使用了 WP_Query 内部过滤器的代码的:

$query = new WP_Query(array('post_type' => array('post', 'page')));

add_filter('posts_where', function($where, $query) {
    // WordPress 6.7 返回 array('post', 'page'),结果为 true
    // WordPress 6.8 返回 array('page', 'post'),结果为 false
    if (array('post', 'page') === $query->get('post_type')) {
        // 修改 WHERE 子句
    }
    return $where;
}, 10, 2);

怎么办呢?比较数组内容时,推荐使用 empty(array_diff(/* arrays */)) 而非直接相等比较,这样就没有顺序的问题。

总结一下

简单说,WordPress 6.8 可以把之前一些因为参数顺序不同的具有等效参数的查询认为是同一个查询,来提升缓存的命中率,从而提高 WordPress 的效率,这个优化还是非常好的,但是也要注意因为对于参数进行排序,而造成的获取数据和之前不同,以及比较的一些问题。

此外该优化不仅仅应用于 WP_Query 这个主要的查询类中,下面这些查询类也有同样的优化和改进:

  • WP_Term_Query
  • WP_Network_Query
  • WP_Site_Query
  • WP_Comment_Query

©我爱水煮鱼,本站推荐使用的主机:阿里云,国外主机建议使用BlueHost

本站长期承接 WordPress 优化建站业务,请联系微信:「chenduopapa」。