各国邮编的系列网站是用Drupal 6搭建的,当初都开启了Pathauto, Boost等模块,使用起来也都还正常,后来将一部分网站进行了50种多语言和手机版的扩充,访问速度就感觉要慢一些,最近一两个月来扩充得越多就感觉网站访问越慢,而且后来取消了Boost缓存(因为没有那么大的硬盘来缓存100倍的文件,即使可以放得下,文件数量太多访问也慢)后感觉更慢了一些。
这个问题先在google webmaster tools中有所发现,但直到最近操作越来越慢才引起重视,监控软件的报错也开始频繁,昨天再一查监控软件的记录,这个系列的子网站打开首页都需要20秒以上,基本上没有办法正常使用了,必须尽快解决、马上解决。
昨天就开始找办法,先以为是Views引起的,对一些MySQL字段添加索引后依然没有解决,再安装Devel仔细排查SQL语句,发现有过多的drupal_lookup_path,一个首页就达到100多条在url_alias表中查找路径的语句,网上资料有人说遇到类似问题,主要有两种解决办法:
- 一是修改includes/path.inc;
- 二是安装cachepath模块。
后者只是对每个页面的drupal_lookup_path进行缓存,第一次缓存依然需要花很长时间,而我看到很多drupal_lookup_path语句都没有必要,所以还是想用第一种办法。
本来Drupal是不建议修改核心模块文件的,但也没有更好的办法,网上别人做的patch实际上也就是修改includes/path.inc,他们改这个文件有两个作用:
- 一是增加查询的缓存;
- 二是排除一些不必要的查询。
其中第一条我没有搞得很懂,第二条我觉得是有必要的,因为Devel看到一些查询语句根本没有必要,在MySQL中看看需要查询的表就知道根本就查不到结果,我没有采用src中建黑名单的方式,而是src中建白名单,只有网址开头是node、user和taxonomy这3种方式才查询数据库,这样修改后页面中的查询数量减少了大约一小半,MySQL的进程数明显减少,一个典型网页打开时间从约25秒减少到15秒左右。
但这样还是不够的,又用Devel追踪发现每个页面都有的50种语言链接也在使用drupal_lookup_path语句,查询的网址是一样的,而语言不同,其实我们所有语言的网址都是一样的,这50个不同的查询其实可以改为同一个查询执行50遍,这样可以利用MySQL本身的查询结果缓存来加速,于是再改path.inc,去掉了查询语句中与语言有关的内容,这一下效果非常明显,一个典型网页打开时间可以小于5秒了,基本上算是正常访问了!
最后把源代码记录如下:
// Get the most fitting result falling back with alias without language //jamesqi 2013-3-6 $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND language IN('%s', '') ORDER BY language DESC, pid DESC", $path, $path_language)); //start modify $path05=substr($path,0,5); $path014=substr($path,0,14); if ($path05=='node/' || $path05=='user/' || $path14=='taxonomy/term/') { $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' ORDER BY pid DESC", $path, $path_language)); } else { $alias = FALSE; } //end modify $map[$path_language][$path] = $alias; return $alias; } // Check $no_src for this $path in case we've already determined that there // isn't a path that has this alias elseif ($action == 'source' && !isset($no_src[$path_language][$path])) { // Look for the value $path within the cached $map $src = FALSE; if (!isset($map[$path_language]) || !($src = array_search($path, $map[$path_language]))) { // Get the most fitting result falling back with alias without language //jamesqi 2013-3-6 if ($src = db_result(db_query("SELECT src FROM {url_alias} WHERE dst = '%s' AND language IN('%s', '') ORDER BY language DESC, pid DESC", $path, $path_language))) { if ($src = db_result(db_query("SELECT src FROM {url_alias} WHERE dst = '%s' ORDER BY pid DESC", $path, $path_language))) { //end modify $map[$path_language][$src] = $path; } else { // We can't record anything into $map because we do not have a valid // index and there is no need because we have not learned anything // about any Drupal path. Thus cache to $no_src. $no_src[$path_language][$path] = TRUE; }
评论