WordPress 6.0 对性能提升还是做了很多工作的,比如昨天文章介绍的新增了批量添加、设置和删除一组缓存的函数,对分类模式下各种查询也进行提升。
分类查询缓存改进
从 WordPress 4.6 版开始,WP_Term_Query
的查询就可以缓存,WordPress 6.0 改进了这些缓存的准备和处理方式。
移除缓存过期事件
WordPress 6.0 之前,如果使用 Memcached 这类外部缓存,分类模式查询的缓存最长24小时,现在这个限制被移除了,所以如果缓存没有失效,那么分类模式查询就会被缓存更长的时间,这样会显著提高站点性能。
查询缓存只缓存 Term ID
分类模式查询的缓存修改成只缓存 Term ID 而不是整个 Term 对象,这样存储在缓存中的对象将会更加的小,如果使用 Memcached 这类外部缓存,可以更省空间。
因为只缓存 Term ID,那么下次从缓存中获取所有 ID 的时候,WordPress 会调用 _prime_term_cache
函数,检测对应 Term 是不是在缓存中,如果不在,它会一次把所有 Term 加载到缓存中,如果已经在了,则不会重复加载。
这些改进都会对性能的提升有好处,因为 WordPress 很多函数的调用都会多次请求一个 Term 的数据,比如标签页,就会一开始通过 get_term_by
函数准备好 Term 缓存,还有其他的函数比如 get_the_terms
也会在内存中准备好 Term 缓存,所以在大多数情况下,这些优化都会减少分类模式相关数据表的查询。
改进查询缓存 key 生成规则
如上所述,现在所有查询只获取 Term ID,所以很多相似的查询,它们缓存的内容都是相同的,比如使用 get_terms
去获取所有分类信息,第一次获取 slug 字段,第二次获取名称,两次查询应该会命中相同的缓存。
另外对传递给 WP_Term_Query
的查询参数的处理也进行了优化,比如 slug 字段可能是字符串,也可能是数组,现在统一转换成数组,这样无论你传递什么类型的参数,缓存的 keys 相同的可能性更高,缓存命中率也提高了。
提高导航菜单的性能
在获取导航菜单的 wp_get_nav_menu_items
函数中,首先使用简单的 taxonomy query 代替 get_objects_in_term
函数,这个替换首先可以把两次数据库查询降低到一次,这样每次获取菜单都能节省一次 SQL 请求,并且还能保持数据的一致性。
此外如果菜单中含有分类和文章的数据,wp_get_nav_menu_items
会改成使用 _prime_term_cache
和 _prime_post_cache
来准备 term 和 post 的缓存,这两个函数的使用会使得获取菜单的数据库请求变得更少,效率更高。
term_exists 使用 get_terms 处理
term_exists
函数内部从使用非缓存的数据库查询转换成使用 get_terms
( WP_Term_Query
) 来处理,这个函数是最后一个对 terms
数据库表执行原始数据库查询的函数,改用 get_terms
函数有下面这些好处:
- 保持和其他核心函数一致,如
get_term_by
- 支持对结果过滤的能力
get_terms
结果是缓存的
term_exists
本来适用于在写入数据库之前的数据重复性检测,然后这个函数被很多插件和主题开发者使用了,这样就造成了站点很多地方有未缓存和未过滤的查询结果。
现在 term_exists
改用 get_terms
处理之后,数据是缓存的,如果你还需要获取未缓存的结果,有两个方法:
- 使用
term_exists_default_query_args
filter
$callback = function ( $args ) {
$args['cache_domain'] = microtime();
};
add_filter( 'term_exists_default_query_args', $callback );
$check = term_exists( 123, 'category' );
remove_filter( 'term_exists_default_query_args', $callback );
wp_suspend_cache_invalidation
wp_suspend_cache_invalidation( true );
$check = term_exists( 123, 'category' );
wp_suspend_cache_invalidation( false );
WordPress Taxonomy Cache Fix
但是经过测试,WordPress 6.0 升级还造成了 child_of 参数的失效,我写了一个小插件修复了该问题。