我尝试着按照各种提速建议作了调整,可是速度没有大的改观,也只好将就。有一天,我突然发现自己在WordPress.com 的博客跑得飞快。两相比较之下,我就再也受不了自己这个博客的蜗牛速度了。我的网站在Dreamhost 的空间上,shared hosting的性能与带宽自然无法和专用主机相比。不过,我还是觉得,速度慢到这种地步,应该有很大的改进空间。如果在页脚模板加上这句:

那么显示页面生成时间在3~6秒之间。就算打开了wp-cache,速度还是慢得令人抓狂。于是我开始了寻找速度提升之路的过程。

首先我很明确的是,目前的这一堆插件,我是一个都不愿意去掉的。

我花了很多功夫东敲西打。甚至连php.ini都又翻出来收拾了几遍(我用自己装的PHP 4.4.2)。后来,在打开phpMyadmin看数据表的时候,发现了一点端倪。

我发现wp_options这张表异常的大。我这里有两张数据表是上MB等级的,一个是wp_falbum_cache。这个好理解。因为里面存储的是FAlbum插件缓存下来的Flickr图片,而且只在专门的相簿页面才加载,不会拖累整体系统性能的。另外一个就是wp_options,也有四、五兆之大。这就相当诡异了。因为wp_posts不过才几百KB,每天都收不少垃圾留言的wp_comments也还没到1MB呢。而且,打开每个前台页面都会查询wp_options表。如果我们研究一下wp-includes/functions.php,可以发现其中的get_option()函数是这样运作的:

$alloptions = wp_load_alloptions();

它调用了另一个叫做wp_load_alloptions()的函数,把wp_options表里的所有记录全部取出放在一个数组变量里面。而这个wp_load_alloptions()函数中的的关键内容就是:

SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'

然后再根据调用get_option()时候的参数来取得具体某个option_name的option_value。当然,对于$alloptions这个变量WP有相应的缓存机制,所以每个页面打开的时候,这个变量只要查询一次,就可以用来获取所有option_name的值。但是,这个表有几兆之大呀,这究竟会不会影响速度呢?

于是我在页脚模板里面加上这句:

queries); ?>

这样就可以详细察看所有SQL查询的耗时信息了。一看之下,大惊失色。就是之前列出的这句SQL花费了0.x秒甚至1.x秒的时间。作为参照来看,其他所有的SQL查询都是0.0x秒。差了一个数量级。所以,在每个页面都要反复查询这些尺寸很大的数据,很不经济呀。

既然问题明确了,我就开始一条一条地翻看wp_options里面究竟有些什么,竟然把数据表撑到几兆之大!

我总结了一下,大概有以下三种信息:

  1. WP自己的设置信息
  2. 插件的设置信息
  3. 一些以rss_开头的纪录

主要问题集中在第二、第三这两项上。如果你想我一样每天不装上一两个插件就浑身不自在,而且频繁安装卸载插件的话,第二项就是一个大问题。因为卸载插件以后,在数据表里的设置信息仍然保留着!有的插件(比如WP-ECommerce),一下子就在wp_options表里面扔了几十条纪录。如果这样的插件来上四五个,林林总总的残留纪录就是个可观的数目了。

对于这个问题没有好的解决办法,只能一条一条删除了。不过,好在就算误删除问题也不大,把相关的插件重新禁用再激活一下应该就可以了。

第三项其实才是本文的重点内容。在我删除了这些rss_纪录之后,wp_options的大小只有60多KB!它们究竟是什么呢?其实就是缓存下来的RSS内容。大致包括了两类:

第一类,就是WP后台里控制面板首页的那些RSS。具体来说有三个,在wp-admin/index-extra.php里面一目了然,分别是

1. Incoming Links:

$rss = @fetch_rss('http://feeds.technorati.com/cosmos/rss/?url='. trailingslashit(get_option('home')) .'&partner=wordpress');

2. Dev News

$rss = @fetch_rss('http://wordpress.org/development/feed/');

3. Planet News:

$rss = @fetch_rss('http://planet.wordpress.org/feed/');

第二类,就是你的Blogroll/链接栏目里面网站的RSS(前提是你在添加链接的时候填写了相应的RSS地址)。为什么呢?因为如果打开菜单 > 选项 > 杂项页面,就会发现WP有个功能是跟踪书签更新时间。在有些模板里,凡是最近有更新的网站,这个书签是用斜体或者其他颜色凸出显示的。这个功能需要抓取RSS来判断更新时间。

所以,这些rss_纪录对于普通的前台页面来说,根本就是冗余无用的。不过,只是删除它们是没用的,因为WP定时更新这些数据的。如果只在数据库里面删除它们,那么过不了多久就又回来了。真是讨厌啊… 而且,毕竟这些数据还是有用的(比如在后台的控制面板页面)。因此,如果你像我一样决定要对付这些记录的话,恐怕就非得修改代码不可了(也就是Hacking了,所谓get your hands dirty罗,呵呵)。

我的解决方案是个笨办法,就是另外建立一张叫做wp_rss_data的数据表,把那些rss_开头的数据记录统统存放在这里。

表的结构可以通过在phpMyadmin里面复制wp_options得来,一模一样的就可以了。然后呢,修改wp-settings.php。在这句的后面

$wpdb->usermeta = $wpdb->prefix . 'usermeta';

加上:

$wpdb->rss_data = $wpdb->prefix . 'rss_data';

在这句的后面

require (ABSPATH . WPINC . '/functions.php');

加上:

require (ABSPATH . WPINC . '/functions-rss.php');

新加入一个文件叫做functions-rss.php,下载点此,要放在wp-includes目录下面。

最后,修改wp-includes/rss.php,把其中的以下变量进行替换:

  1. $wpdb->options 替换为 $wpdb->rss_data
  2. add_option 替换为 add_rss_data
  3. update_option 替换为 update_rss_data
  4. get_option 替换为 get_rss_data

完成了。这是一个涉及代码修改的办法,所以请做好备份。我不保证没有问题哦。总的概念就是,把rss.php中涉及wp_options表的操作都转移到刚才建立的wp_rss_data表。而相关的函数都在添加的functions-rss.php中提供了(其实是一模一样从xxx_options拷贝过来的)。我也想过在add_option,update_option,get_optoin函数中加入判断,来分别是一般的option_name还是rss_那样的,然后操作不同的数据表。不过后来觉得这样修改不利于升级,所以还是用了现在的办法。

现在我的wp_options表一般在60-100多KB之间,wp_rss_data表一般在4~5MB左右。WP系统的整体速度令我满意(因为就算打开了wp-cache插件来缓存页面,这个wp_options表还是每次都要查询的)。

最后指出一点,使用很广泛的Sitemap 插件会在wp_options表中存储生成sitemap的过程信息。这条纪录也略有点大,如果你是个完美主义者,那就记得点一下Clear Log按钮来清除。

就写到这里吧,下次再见吧~