WordPress文章量大时分类列表查询缓慢的一种优化方案

很多朋友时常会关注WordPress适不适合做大站比如上百上千万的文章,这个问题认真地问答起来其实也不容易,只能说既不适合也适合。

不适合说的是WordPress功能强大的背后就是臃肿,运行海量级数据可能就有点龟速了。适合的意思是WordPress通过更好地优化也可以运行大型数据库及复杂的查询。

例如,WordPress分类列表下有了10万篇文章时,查询的速度缓慢得不行了。很多情况下,即使使用到了缓存,还是无法从根本上解决问题,因为问题的改善可能要通过数据库入手。

一般情况下,查询category和post_tag下的文章时,需要同时关联到两张表:wp_posts和wp_term_relationships。
通常SQL语句。示例,除了的category和post_tag,新增了一个名为kind的分类法。
查询出同时归属于categoryID为1,kind的ID为2的文章:
参数:
$args = array(
'post_type'=>'post',
'tax_query'=>array(
'relation'=>'AND',
array(
'taxonomy'=>'category',
'field'=>'term_id',
'operator'=>'IN',
'terms'=>array(1)
),
array(
'taxonomy'=>'kind',
'field'=>'term_id',
'operator'=>'IN',
'terms'=>array(2),
)
)
);
query_posts($args);

SQL语句:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) LEFT JOIN wp_term_relationships AS tt1 ON (wp_posts.ID = tt1.object_id) WHERE 1=1 AND (
wp_term_relationships.term_taxonomy_id IN (1)
AND
tt1.term_taxonomy_id IN (2)
) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10
这是一条慢查询SQL语句,文章量大时就耗时长了。

一种优化方案就是减少数据表的查询,将category和post_tag变通式地放入wp_posts。例如在wp_posts表中增加一个kind字段,用来存储器中的一个分类的信息。

首先,在启用主题的时候,执行sql在wp_posts表中增加kind_id字段,并加上Index索引。
//激活主题时执行
function ashu_add_pages() {
global $pagenow;
if ( 'themes.php' == $pagenow && isset( $_GET['activated'] ) ){
ashuwp_alter_posts_table();
}
}
add_action( 'load-themes.php', 'ashu_add_pages' );
//修改posts表,增加一列kind_id
function ashuwp_alter_posts_table(){
global $wpdb;
//判断字段是否已经存在
$sql1 = "Describe {$wpdb->posts} `kind_id`";
$kind_id_exist = $wpdb->query($sql1);
if( !$kind_id_exist ){
//新增列
$add_column = "ALTER TABLE {$wpdb->posts} ADD COLUMN `kind_id` INT(10) DEFAULT NULL";
$wpdb->query($add_column);

//添加索引
$add_index = "ALTER TABLE {$wpdb->posts} ADD INDEX kind_id (`kind_id`)";
$wpdb->query($add_index);
}
}
第二步:将kind分类的ID信息保存到wp_posts表中的kind_id字段。这里使用set_object_terms钩子,就是在设置分类的时候用,当然为了避免发布文章的时候后台多选,这里只保存一个ID数据。
add_action( 'set_object_terms', 'ashuwp_add_post_kind_id', 10, 6);
function ashuwp_add_post_kind_id( $object_id, $terms, $tt_ids, $taxonomy, $append = false, $old_tt_ids = array() ){
global $wpdb;
if( $taxonomy=='kind' ){
$term_id = reset( $tt_ids );
if( $term_id ){
$sql = "UPDATE {$wpdb->posts} SET `kind_id`={$term_id} where `ID`={$object_id}";
$wpdb->get_results( $sql );
}
}
}
第三步:使用WP_Query等查询文章时直接传入kind_id参数,改善原来的JOIN关联表查询
function ashuwp_query_posts_where( $where, $query){
global $wpdb;
$qv = $query->query_vars;
isset( $qv['kind_id'] ) AND $kind_id = absint($qv['kind_id']) AND $where .= " AND {$wpdb->posts}.kind_id = {$kind_id}";
return $where;
}
add_filter( 'posts_where', 'ashuwp_query_posts_where', 10, 2);
调用方法:
使用WP_Query等查询文章时,使用kind_id参数来定义分类
$args = array( 
'post_type'=>'post',
'kind_id'=>2, //直接使用kind_id做参数
'tax_query'=>array(
array(
'taxonomy'=>'category',
'field'=>'term_id',
'operator'=>'IN',
'terms'=>array(1)
)
)
);
query_posts($args);
注:说白了,就是将分类放入同一张posts表中。
有细心的伙伴可能问了,既然如此WordPress为什么不直接设计将categosy放在wp_posts表中,还要分两张表。没错,WordPress最早时categosy和post本来就是在一张表中,好象WordPress3.x后才分开的,WordPress3官方解释说是为了更好地保持系统的继承性,毕竟WordPress有海量的插件和工具贡献者。
(本文完,参考资料:创客)

#现在前往

精选留言

WordPress,文章,量大,分类
sample
2021-05-17
写留言
签到
投稿
QQ咨询
返回顶部