我们可以做很多事情来提高代码的性能。让我们先设置一些基准
基准点我正在用
category
分类术语,有9个职位和在post_tag
具有61个匹配标记的分类法。
根据您当前的代码,我得到以下结果
对于这样一个小的数据库和测试主题,这是非常昂贵和大量的查询优化我们要做的第一件事是只从帖子中查询帖子ID,原因如下
我们不需要任何post数据
我们不需要更新后缓存和后元缓存,我们不需要
显然,只有查询帖子ID才能大幅提高性能
仅查询ID有一个缺点,即我们还失去了术语缓存。因为我们不更新术语缓存,这将导致db查询的大量增加。为了解决这个问题,我们将使用
update_object_term_cache
.
到目前为止,仅在您的查询中,您就获得了1db的调用和0.02s,这并不多,但它对一个巨大的数据库有很大的影响。真正的收益将在下一节中介绍
真正大的好处是将object一词传递给get_term_link()
, 而不是术语ID。如果术语缓存中没有术语,则将术语ID传递给get_term_link()
, 而不是从缓存中获取术语对象,get_term_link()
将查询db以获取术语对象。仅在测试中,这相当于额外的61 db调用,每个标记一个。想想几百个标签。
我们已经有了术语对象,所以我们可以简单地传递完整的术语对象。你应该一直这样做。即使术语对象在缓存中,传递术语ID的速度仍然非常慢,因为我们仍然必须从缓存中获取术语对象
我已经清理了你的代码。注意,我使用了短数组语法,它确实需要PHP 5.4+。下面是您的代码的外观
$category = get_category( 13 ); // JUST FOR TESTING< ADJUST TO YOUR NEEDS
$args = [
\'post_type\' => \'product\',
\'fields\' => \'ids\', // Only query the post ID\'s, not complete post objects
\'tax_query\' => [
[
\'taxonomy\' => $category->taxonomy,
\'field\' => \'slug\',
\'terms\' => $category->slug
]
]
];
$ids = get_posts( $args );
$links = [];
// Make sure we have ID\'saves
if ( $ids ) {
/**
* Because we only query post ID\'s, the post caches are not updated which is
* good and bad
*
* GOOD -> It saves on resources because we do not need post data or post meta data
* BAD -> We loose the vital term cache, which will result in even more db calls
*
* To solve that, we manually update the term cache with update_object_term_cache
*/
update_object_term_cache( $ids, \'product\' );
$term_names = [];
foreach ( $ids as $id ) {
$terms = get_object_term_cache( $id, \'post_tag\' );
foreach ( $terms as $term ) {
if ( in_array( $term->name, $term_names ) )
continue;
$term_names[] = $term->name;
$links[$term->name] = \'<li><a href="\' . get_term_link( $term ) . \'">\' . $term->name . \'</a></li>\';
}
}
}
if ( $links ) {
ksort( $links );
$link_string = implode( "\\n\\t" , $links );
} else {
$link_string = \'\';
}
echo $link_string;
目前,我们已将人数减少到
6 db queries in 0.04s 这是一个巨大的进步。
我们甚至可以更进一步,将结果存储在瞬态中
$category = get_category( 13 ); // JUST FOR TESTING< ADJUST TO YOUR NEEDS
$link_string = \'\';
$transient_name = \'query_\' . md5( $category->slug . $category->taxonomy );
if ( false === ( $link_string = get_transient( $transient_name ) ) ) {
$args = [
\'post_type\' => \'product\',
\'fields\' => \'ids\', // Only query the post ID\'s, not complete post objects
\'tax_query\' => [
[
\'taxonomy\' => $category->taxonomy,
\'field\' => \'slug\',
\'terms\' => $category->slug
]
]
];
$ids = get_posts( $args );
$links = [];
// Make sure we have ID\'saves
if ( $ids ) {
/**
* Because we only query post ID\'s, the post caches are not updated which is
* good and bad
*
* GOOD -> It saves on resources because we do not need post data or post meta data
* BAD -> We loose the vital term cache, which will result in even more db calls
*
* To solve that, we manually update the term cache with update_object_term_cache
*/
update_object_term_cache( $ids, \'product\' );
$term_names = [];
foreach ( $ids as $id ) {
$terms = get_object_term_cache( $id, \'post_tag\' );
foreach ( $terms as $term ) {
if ( in_array( $term->name, $term_names ) )
continue;
$term_names[] = $term->name;
$links[$term->name] = \'<li><a href="\' . get_term_link( $term ) . \'">\' . $term->name . \'</a></li>\';
}
}
}
if ( $links ) {
ksort( $links );
$link_string = implode( "\\n\\t" , $links );
} else {
$link_string = \'\';
}
set_transient( $transient_name, $link_string, 7 * DAY_IN_SECONDS );
}
echo $link_string;
这将使一切减少到
2 queries in 0.002s. 有了临时版本,我们将在发布、更新、删除或取消删除帖子时刷新临时版本。我们将使用
transition_post_status
钩住这里
add_action( \'transition_post_status\', function ()
{
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient%_query_%\')" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE (\'_transient_timeout%_query_%\')" );
});