wordpress支撑百万文章解决方案

无论是从功能方面还是开发方面,wordpress用起来都很便利,但便利的背后是以牺牲明能为代价的。最近想着优化一下wordpress,看看有没有什么方案能够将wordpress支撑起百万的数据呢。

支撑百万数据并不是存入一百万文章就可以了,实际上百万文章对mysql来说毫无压力,别说百万了,上亿也没什么关系,有关系的是查询。很不幸,如果主题写的不好,百万文章的wordpress查询就是个灾难。

从首页开始看

一般来说,达到百万文章级别的站点,首页应该是一个展示很多分类文章的页面。但是由于wp在初始化的时候就会根据url中的查询去数据库查询一些文章,首页是根据时间倒序查询,因此当不需要最新文章的时候,可以利用钩子去掉这部分查询。当需要最新文章的时候,也需要优化这个查询,默认的查询是带有SQL_CALC_FOUND_ROWS,这个简直是性能杀手!
当需要从分类取出一些数据的时候,使用WP_Query构造出的查询也会用到filesort,因此可以选择构建一张表,作为中间查询。

文章页面

看看文章页面,似乎没有什么费时间的查询,基本上就是id查询内容,用到了索引,但是其中有一个翻页的问题,其中有一个翻页的功能是可以筛选出相同分类的上下篇文章,这种查询的sql语句如下

mysql> SELECT p.ID FROM wp_posts AS p
  
INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE p.post_date > '2017-07-04 09:57:50' AND p.post_type = 'post' AND tt.taxonomy = 'category' AND tt.term_id IN (4) AND p.post_status = 'publish' ORDER BY p.post_date ASC LIMIT 1;

使用explain看看

mysql> explain SELECT p.ID FROM wp_posts AS p INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE p.post_date > '2017-07-04 09:57:50' AND p.post_type = 'post' AND tt.taxonomy = 'category' AND tt.term_id IN (4) AND p.post_status = 'publish' ORDER BY p.post_date ASC LIMIT 1\G
 *************************** 1. row ***************************
 id: 1
 select_type: SIMPLE
 table: tt
 type: const
 possible_keys: PRIMARY,term_id_taxonomy,taxonomy
 key: term_id_taxonomy
 key_len: 106
 ref: const,const
 rows: 1
 Extra: Using temporary; Using filesort
 *************************** 2. row ***************************
 id: 1
 select_type: SIMPLE
 table: tr
 type: ref
 possible_keys: PRIMARY,term_taxonomy_id
 key: term_taxonomy_id
 key_len: 8
 ref: const
 rows: 5576
 Extra:
 *************************** 3. row ***************************
 id: 1
 select_type: SIMPLE
 table: p
 type: eq_ref
 possible_keys: PRIMARY,type_status_date
 key: PRIMARY
 key_len: 8
 ref: aikanwen.tr.object_id
 rows: 1
 Extra: Using where
 3 rows in set (0.19 sec)

看起来就是个灾难现场,这种查询会随着分类的增加而变得奇慢无比,因为有时候分类和标签可能会达到几万几十万个!

分类页面

同首页。

插件

wordpress最常用的插件可能是wp_postviews了,但是对于百万文章的wordpress来说,这个插件可能是个灾难,如果你用到了它的排行榜的话。

这个排行榜会使用一个如下的查询

SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( 
 wp_postmeta.meta_key = 'views'
) AND wp_posts.post_type IN ('post', 'page', 'attachment') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value+0 DESC LIMIT 0, 10;

这种查询也是一个灾难,对于wp来说,wp_post_meta表中根本没有meta_key 和 meta_value的索引,也是根本无法使用索引做排序,所以只能使用filesort,需要全表扫描。可以看看explain。

mysql> explain SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( wp_postmeta.meta_key = 'views' ) AND wp_posts.post_type IN ('post', 'page', 'attachment') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value+0 DESC LIMIT 0, 10 \G;
 *************************** 1. row ***************************
 id: 1
 select_type: SIMPLE
 table: wp_postmeta
 type: ALL
 possible_keys: post_id,meta_key
 key: NULL
 key_len: NULL
 ref: NULL
 rows: 67053
 Extra: Using where; Using temporary; Using filesort
 *************************** 2. row ***************************
 id: 1
 select_type: SIMPLE
 table: wp_posts
 type: eq_ref
 possible_keys: PRIMARY,type_status_date,post_author
 key: PRIMARY
 key_len: 8
 ref: aikanwen.wp_postmeta.post_id
 rows: 1
 Extra: Using where
 2 rows in set (0.17 sec)

这种排序一次,基本就是个灾难。别说百万,十万文章蜘蛛都能搞挂了。

最后我放弃优化了,还是重新构建一个能过支撑百万级别的数据库结构比较简单。wordpress本身定位就是博客,放太多的数据查询起来太慢了。

赞赏

微信赞赏支付宝赞赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注