WP_Query
是 WordPress 中最重要的 class,几乎每个页面都是用它来获取文章,但是它最大的问题是,对文章进行查询的时候是直接到数据库查询的,结果没有被缓存起来,所以真正实现站点的 0SQL 最后的问题就是这里。
我之前也通过各种方式实现了0SQL,其中应用到了 Autumn Pro 和免费的 Sweet 主题上,现在官方实现了 WP_Query 数据库查询缓存,对 WordPress 整个性能提升肯定有显著的帮助。
WP_Query 实现数据库查询缓存
WordPress 6.1 改进了 WP_Query 类中数据库查询的执行方式,实现 SQL 查询缓存,这意味着如果多次运行同一条 SQL 查询,查询结果将从缓存中加载。
对于使用持久对象缓存服务(比如 Memcached)的站点来说,在缓存失效之前,相同的数据库查询就不会再次运行,从而显著降低站点的数据库查询次数。
对于未使用内存缓存的站点来说,同个页面中相同的 WP_Query 也也不会重复执行,所以站点性能也会得到一定提升,但是不会那么显著。所以这也是我一直强调 WordPress 站点一定要安装 Memcached 的原因。
WP_Query
实现数据库查询缓存是有一套自己的实现机制,所以对于插件和主题开发者来说,如果要对文章进行操作的话,最好使用 WordPress 提供的文章操作函数。
比如使用 wp_insert_post
函数将文章添加到数据库,这些函数会自动去清理缓存,这样下次使用 WP_Query 获取文章时候,获取到的是包含了新增的或者更新之后的数据。
如果直接使用 SQL 语句更新到数据库的话,则强烈建议执行之后,使用 clean_post_cache
函数对缓存进行清理。
如何禁用缓存
值得注意的是,在默认情况下,WP_Query
的所有数据库查询都将被缓存,如果想不缓存,只需将 cache_results
参数设置为 false
即可:
$query = new WP_Query(array(
'posts_per_page' => 50,
'cache_results' => false
));
也可以通过 filter 全局禁用缓存:
add_action('parse_query', function($wp_query){
$wp_query->query_vars['cache_results'] = false;
});
禁用缓存只是在一些极端的情况下使用,为了获得最佳性能,强烈建议保持缓存开启,如要清理缓存使用 clean_post_cache
函数。
缓存 key 规则
缓存的键是使用 WP_Query
的查询参数生成的,但是会忽略以下参数:
-
suppress_filters
-
cache_results
-
fields
-
update_post_meta_cache
-
update_post_term_cache
-
update_menu_item_cache
-
lazy_load_term_meta
因为这些忽略的参数不会影响生成的 SQL 语句,其中特别要注意下 fields
参数,这意味着下面这些查询:
$query1 = new WP_Query(array(
'posts_per_page' => 50,
'fields' => 'ids'
));
$query2 = new WP_Query(array(
'posts_per_page' => 50,
'fields' => 'all'
));
上面这两种情况,无论是否使用了 fields
参数,参数的值是什么,SQL 查询是一样的,然后缓存起来,这样就能够更加高效的使用缓存,而无需存储多份缓存数据。
WP_Query 初始化所有作者数据
在 6.1 之前,主循环会同时加载作者信息,所以具有多个作者的站点需要执行多次数据库查询来分别获取作者的信息,现在 WordPress 6.1 引入了一个新函数 update_post_author_caches
,通过在循环开始时调用该函数通过一次数据库查询就初始化所有用户(作者)缓存,而不是逐个加载每个用户,从而减少数据库查询。
此函数接受一个 post 对象数组参数,并将初始化用户缓存,WP_Query
会自定调用 update_post_author_caches
以提高站点性能。
初始化菜单中的所有链接对象
WordPress 6.1 还新增了函数 update_menu_item_cache
,它支持一个 post 的对象数组参数,然后就会初始化菜单中引用到的文章或者分类的数据缓存,并且 WP_Query
也增加了一个新的参数 update_menu_item_cache
,如果它被设置为 true
,则会调用 update_menu_item_cache
函数仅仅通过两条 SQL 查询(一条是关于 posts,一条是关于 terms)就让 WP_Query
获取菜单信息。
get_page_by_title 直接使用 WP_Query
get_page_by_title
函数在 6.1 版本也改用 WP_Query
来获取数据,之前,该函数直接使用 SQL 查询来实现通过标题获取页面,从上可知,WP_Query
查询结果将会被缓存,这意味着现在调用 get_page_by_title
也将会被缓存,当然所有通过 WP_Query
获取数据的函数也将被缓存。