我们在使用 WordPress 建站,特别是一些 CMS 类型的站点,多种分类法是常用的,然而 WordPress 在使用多种分类法混合查询的时候,这个查询Y W c J w 5语句就复杂了,在分类和文章数量多了之后,速度就堪忧了,所以这里提一种优化方案供参考。
举例:某个案例中,对于默认的除了的 category 和 post_tag,新增了一个F t I I ^名P i ? 2 \ y为 kind 的分类法,注册新分类法的步骤这里就不赘述了,% Y d W s K M l然后我们需要查询出同时归属: 8 9 6 o !于 categoi \ S , } L rryID 为 1,kind 的 ID 为 2 的文章,普c ^ / J f V I ^通的做法:
- $args = array(
- 'post_type'=>'post',
- 'tax_query'=>array(
- 'relation'=>'AND',
- array(
- 'taxonomy'=>'category',
- 'field'=&~ S zgt;'term_id',
- 'operator'=>'IN',
- 'terms'=&v $ 5gt;array(1)
- ),
- array(
- 'taxonomy'L m n v j=>. N W Y d;'kind',
- 'field'=>'tl h v :erm_id',
- 'operator'=&N 7 ! P M 8gt;'IN',
- 'terO \ U + G Cms'=>array(2),] S h ]
- )
- )
- );
- query_posts($args);v U 7 9 2 ) 4 ` x
就上S % @ H +面这个查询来说,在没有缓存的情况下要执行 3 次数据库查: \ 5 i l询,前面两次分别查询对应的分类是否存在,重点是第 3 次文章查询,由于 wordpress 分类和文章的对应关系存储 wp_term_re] f , # [ # J t ^latia | T = ~ monships 表中,每篇I # k B文章对应每一个分类都有一条记录,所以查询文章的时候主要要两次 left join 这个 wp_term_relationships 表,一旦数据量多起来,这样的查询g } 7 w . e { o就比较慢了,附打印出的查询语句如下。
- SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_pos0 + h A = z R ~ uts+ P k p b z LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationshipsH | U 8 D . a s p.objecx Z * _ }t_im c O z r T F n Hd) LEFTU [ | 5 f F JOIN wp_t v Eterm_relationships AS tt1 ON (wp_posts.ID = tt1.object_id) WHERE5 D ` 1=1 AND (
- wp_term_relat1 V [ionships.term_taxonomy_S % N sid IN (1)
- AND
- tt1.term_taxonomy_id IN (2)8 Y ! Q S;
- ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_poq = 0 rsts\ I s Y P $.post_status = 'private') GROUP BY wp_posts.g : n G 3 _ ;ID ORDERu 5 0 5 ? l k % BY wp_posts.pV + , N _ A yost_date DESC LIMIT 0, 10
我的解决方案,在 wp_posts 表中增加一个字段,用来存储器中的一个分类的信息,比如这个案例里面我把 kin\ Q c n : y 4 `d 的 I{ G @ L = - OD 信息冗余存储在 wp_posts 表中,然后将查询条件放到 w% W ! )p_posts 表中,这样就能提速了。
第一步:在启用主题的时候,执行 sql 在 wp_posts 表中增加 kind_id 字段,并加上 InJ M 4 _ E t \dex 索引。(在这个案例中因为客户的分类可以确定是单选,所以 kind_id 字段的类型就直接用 int 了,如果你要保存多个分类 ID,v 6 ) N + % $ Z可以改为 varchar 类型,不过 varcharz L g v 7 6 类型就不别弄索引了)。
- //激活主题时执行
- function ashu_add_pages() $ - / T @ 7123;
- global $pagenow;
- if 5 - O l D ~ N040; 'themes.ph ! U ~ + 5 fhp' == $pagenow && isset( $_GET['activated'] ) ){
- ashuwp_alter_posts_table();
- }
- }
- add_action( 'load-themes.php', 'ashu_add_pages' );
- //修改posts表,增加一列kind_id
- function ashuwp_alter_posts_table()&b H N ^ W#123;
- global $wpdb;
- //判断字段是否已经存在
- $sql1 = "Describe {$wd t E z | w 1pdb->posts} `kind_id`";
- $kind_id_exist = $wpdb->query($sql1)K Y @;;
- if( !$kind_id_exist ){
- //新增列
- $add_column = "ALTERq l # L M k r TABLE {$wpdb->posts} ADD COLUMN `kindK s *_id` INT(10) DEFAULT NULL";
- $wpdb->query($ad- x K + y A ` 1 sd_column);
- //添加索引
- $add_index = "ALTER T_ v K l E B | _ 1ABLE {$wpdb->posts} ADD INDEX kind_id (`kind_iZ R o h , u x 6 6d`)";
- $wpdb-&gB t T R U s 9 }t;query($add_index);
- }
- }
第二步:发布y U ! P ^ u }文章的时候,将 kind 分类的 ID 信息保存到 wp_posts 表中的 kind_id 字段。这里使用 set_object_terms 钩子_ g f J 6 p,就是在设置分类的时候用,当然为了避免后台多选,这里只保存一个 ID 数据
- add_action( 'set_objeX 3 ; T i z 0 L hct_terms', 'ashuwp_add_post_kind_id', 10, 6! A z G041;;
- function ashuwp_adE ( # w l . bd_pos% x z l 9 p ^t_kind_id( $object_id, $terms, $tt_ids, $taxonomy, $append = false, $old_tt_x ( I m s F o oids = ap r [ D 1 ? + g rrray() )i 0 x Y R c U3;
- 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}&0 S k l 2 j w ;quot;;
- $wpdb->get_results( $sql );
- }
- }
- }
第三步:我f Q F - x C希望在使用 WP_Q^ p 7 Y 1 9uery 查询文章时直接传入 kind_id 参数即可,所以使用 posts_where 钩子,检测t w E h % _ 8 \ `是否有 kind_id 参数,然后拼接查询语句。
- function ashuwp_query+ 9 W w \ T 7_posts_w\ S rhere( $wh! - 7 C S ^ / 9 ?ere, $query)P 6 6 3 C ] g23;
- global $wpdb;
- $qv = $query->query_vars;
- isset( $qv['kind_id'] ) AND $kind_id = absint($qv['kind_id']) AND $where .= "q Y v * M 7 w u 1; ANR S _ E b V 9D {$wpdb->posts}.kind_id = {$kind_id}";
- return $+ h E r Cwhere;
- }
- add_filter( 'posts_where', 'asG S r 5 Z }huwp_query_posts_where', 10, 2);
第四步:查询文章。最开始那一段查询可m T C ^ p W以直接改成如下代码即可。
- $args = array(
- 'post_type'=>'post',
- 'kind_id'=>2, /G ^ ^ a 6/直接使用kind_id做参数
- 'tax_query'=>array(
- array(
- 'taxonomy'=>'category',
- 'field'=>'term_id',
- 'operaM T 1 ? S R V s +tor'=>'IN',
- 'terms'=>array(1)J ~ S m 0 ^;
- 2 @ d M w M m s041;
- )
- );
- qus 9 u ! K z m 2ery_posts($argsd & L041;;
好了,就到这里,这里在下只是提供了一种 WordPreE 5 ` w 8ss 的查询优化方案,可用此方案自行改造其= n ] P #他应用。