进行SQL查询优化,让wordpress支撑起快速读写百万级文章的数据

wordpress非常便利,但数据量增大后查询会变得缓慢。

这时,必要的优化少不了。

整体优化

需要去掉所有查询中带有的SQL_CALC_FOUND_ROWS,这会扫描表,速度十分慢!对于大量的数据,查询的数目应该是缓存过后,或者是事先计算好的!

需要去掉所有的COUNT操作,这也会导致扫描条件中的所有行,如果条件没有索引,将会导致扫描全表!

由于wordpress查询复杂,针对每一种查询设置一个计数器不太现实,可以考虑使用查询结果缓存的方式来减少扫描全表的次数。缺点就是计数会有延迟。

首页优化

一般来说,达到百万文章级别的站点,首页应该是一个展示很多分类文章的页面。但是由于wp在初始化的时候就会根据url中的查询去数据库查询一些文章,首页是根据时间倒序查询,因此当不需要最新文章的时候,可以利用钩子去掉这部分查询。

文章页优化

看看文章页面,似乎没有什么费时间的查询,基本上就是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)
这种排序一次,基本就是个灾难。别说百万,十万文章蜘蛛都能搞挂了。

事实上,在文章达到百万的时候,大部分插件都不能乱用了,一不小心就会是个灾难。

后台优化

后台页面在打开的时候会查询当前作者的所有文章以及各个状态的文章数量,这会扫描全表,别说百万文章了,就算二十万文章也会卡死。

最好的办法就是去掉这些查询,然而去掉这些查询会让后台展示不正常,因此只能利用缓存将这些数量存起来,这样后台的速度就很快了。虽然会有展示不及时的问题,但是到了这个文章量,这已经不是主要的问题了。

全站缓存

这是最重要的一步了,再多的优化也只能保证你的百万文章站点能正常打开,而加速的最好方法就是缓存,市面上相关的插件非常多,这里就不重复了。

#现在前往

精选留言

进行,SQL,查询,优化
sample
2021-05-28
写留言
签到
投稿
QQ咨询
返回顶部