各國郵編的系列網站是用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; }
评论