Updated: 2008-07-26,更新Hook代码 

续上文,通过WordPress基准页面数据库查询次数统计,让我们对WP运行各页面所需最少查询数有个基本了解。分析这些基准页面所需的数据库查询次数的目的当然是想减低它们,以提高WP运行效率了。本文将就如何不借助外部方法,仅利用Wordpress自带技术来减少Wordpress数据库查询次数和提高运行效率,谈谈我的个人做法和思路。欢迎拍砖。本文假设阅读者应了解WP的基本知识,并能操作简单的PHP代码。

要想减少数据库的查询次数,首先要对模板进行分析,了解到模板中的哪个部分功能需要调用数据库,以及哪些些插件需要读写数据库。然后在此基础上,再来分析下减少的可能性。此文主要以模板为例,插件部分暂且不谈。以ThinkAgain现用模板为例,来分析下页面中的哪几个部分需要读取数据库。如在首页的最新留言,最新存档,目录树和标签云等这些都需要从数据库中读取相应的数据,至于日历,WP已经内置了缓存。进一步考虑下,这些东西在未有新事件前,(如新留言或新文章发布等),每次加载页面读取数据库并生成的html代码的内容都是一样的,既然如此有必要在每次加载页面时,重复这些事情,如果能将这部分内容缓存起来岂不就可以减少数据库读取次数以及提高WP运行效率了吗?OK,这个就是我对精简数据库查询次数的主要思路之一。当然,接下来要解决如何实现缓存问题以及自动更新的问题。

 

先来看一组数据,让数字来说话。

数据库查询次数对比

上图是DH提供的数据库使用情况统计数字,可以看出,从19日到21日,每次数据库链接所消耗的查询次数均值大概在29.1~30.6,22日下午开始换上更改后的代码,启用缓存,22日平均查询次数降低到25.2,23日的平均值就更低了约为20次。大约降低了33%左右。效果还是很显著的吧。

接下来,来谈谈具体如何缓存以及如何解决即时更新的问题。

1. 缓存问题 

缓存数据的方法虽然很多,其实按性质划分起来无非就只有2种,缓存到数据库或者缓存文件。后者,记得水煮鱼写过一篇怎样缓存sidebar的文章,简单地说,其思路为利用output control function将侧边栏内容缓存到sidebar.html文件中,然后定时进行更新。此法可以解决缓存问题以及减少数据库查询,唯一不足的就是在指定间隔时间内容,新留言的无法自动更新。p.s,这问题实际上利用WP运行机制是可以解决的。

而我的方法是将数据缓存到数据库中,然后在使用时仍然从数据库中读取。如此做法不是还要读取数据库么?怎么会减少数据库查询次数呢?先别急,且听我慢慢道来。

默认WP有10个数据表,wp_posts和comments主要存储文章内容和评论,其它的几个包括term等存储了目录和标签等等。这里不细谈。wp_options用来存储Wordpress以及插件运行时所涉及的配置等。且WP会在运行时自动读取该表的内容。换句话说,因为WP已经预读这部分内容,所以直接调用wp_options内的数据是不会产生数据库查询的。到此为止,谜底已经揭开了一大半了。高手们不用往下看,也都知道怎么做了吧。呵呵。 

2. 即时更新问题

有了新留言或发布了新文章,自然想马上在页面中显示出来,这就需要即时更新已缓存在wp_options里面的数据。要解决这个问题,自然还是要从Wordpress的运行机制方面下手。

此文中,我曾简单地谈过WP是个好东西,提供了一个框架平台,也开放了很多预定义的接口给用户自定义。从系统分析的角度来看,WP也是个离散系统。从用户点击网址,WP解析url开始等,发表评论或文章等等,这些都可以视为一个离散事件。而WP提供了很完备的Hook用于用户对这些事件进行控制。 

缓存的内容涉及最新留言,或文章数的显示等,这些无非都需要在新留言或新文章发布这些事件发生后激活更新缓存。理解了这点,也就很容解决问题了。发布新留言和新文章的Hook接口为:

add_action(‘comment_post’, ‘Your_Function’); //comment发布Hook

add_action(‘publish_post’, ‘Your_Function’); //post发布Hook 

2个问题都清楚,画个流程图也很简单了。

流程图

行文至此,我已经将这个问题的Know-How解释清楚了。老鸟么,可以到此止步。小鸟们继续往下看我给的一个例子。 

下面我将给出一个自己写的将最新留言缓存到wp_options表中,以及读取最新留言的2个函数(共3个函数)。有兴趣可以Copy下来放在自己模板的Function.php中,就可以激活使用了。然后在侧边栏的显示最新留言位置,将原来代码替换成

<?php cache_recent_comments();?>

就可以了。 

简单介绍下,cache_recent_comments()函数用来显示缓存后的最新留言,cache_get_recent_comments()用来获取最新留言并缓存到wp_options表中。my_utf8_trim(),这个函数是中文工具箱的,其作用在于避免留言被截断后尾部出现乱码。在这里放上来,免得有些网友没有装中文工具箱造成不便。

   1: //显示缓存后的最新留言
   2: function cache_recent_comments(){
   3:     $cached = get_option('multicolor_cache_recent_comments');//从options表中获取已缓存的最新留言
   4:     if($cached){    //如果最新留言已缓存,直接显示,否则获取最新留言并缓存到options表中。
   5:         echo $cached; 
   6:     }else{
   7:         $cached = cache_get_recent_comments();
   8:         echo "Cache Updated";
   9:         echo $cached;
  10:     }
  11: }
  12: //获取最新留言并缓存到options表中
  13: function cache_get_recent_comments() {
  14:     $commentnumber = 6;    //显示最新留言数目
  15:     $before = '<li> ';    //留言前后html标签
  16:     $after = '</li>';    
  17:     $length = 150;        //截取留言的长度
  18:     global $wpdb;
  19:     $sql = "SELECT ID, comment_ID, comment_author_url, comment_content, comment_author FROM $wpdb->posts, $wpdb->comments WHERE $wpdb->posts.ID=$wpdb->comments.comment_post_ID AND ($wpdb->posts.post_status = 'publish')";
  20:     $sql .= "AND comment_approved = '1' ORDER BY $wpdb->comments.comment_date DESC LIMIT $commentnumber";
  21:     $comments = $wpdb->get_results($sql);
  22:     $output = '';
  23:     foreach ($comments as $comment) {
  24:         $comment_author = stripslashes($comment->comment_author);
  25:         $comment_author_url = stripslashes($comment->comment_author_url);
  26:         $comment_content = strip_tags($comment->comment_content);
  27:         $comment_content = stripslashes($comment_content);
  28:         $comment_excerpt =substr($comment_content,0,$length);
  29:         $comment_excerpt = convert_smilies($comment_excerpt);
  30:         $comment_excerpt = my_utf8_trim($comment_excerpt);
  31:         $permalink = get_permalink($comment->ID)."#comment-".$comment->comment_ID;
  32:         if (!empty($comment_author_url)){
  33:         $comment_author_link = '<a style="font-style: italic;color:#444;border-bottom:1px dashed #888" title=" '. $comment_author_url.'" target="_blank" href="'. $comment_author_url . '">'. $comment_author . '</a>';
  34:         }else{
  35:             $comment_author_link = '<a style="font-style: italic;color:#444;border-bottom:1px dashed #888" title=" View the entire comment by ' . $comment_author . '" target="_blank" href="'. $permalink  . '">'. $comment_author . '</a>';
  36:         }
  37:         $output .= $before . $comment_author_link . ': ' . '<a target="_blank" href="' . $permalink . '" title="View the entire comment by ' . $comment_author . '">'  . $comment_excerpt . '...' . '</a>'  . $after;
  38:         }
  39:         update_option('multicolor_cache_recent_comments', $output); //更新缓存在options表中的最新留言
  40:         return $output;
  41: }
  42: //中文工具箱的函数,用于砍掉汉字截断尾巴可能存在的乱码。
  43: function my_utf8_trim($str) {
  44:     $len = strlen($str);
  45:     for ($i=strlen($str)-1; $i>=0; $i-=1){
  46:         $hex .= ' '.ord($str[$i]);
  47:         $ch = ord($str[$i]);
  48:         if (($ch & 128)==0) return(substr($str,0,$i));
  49:         if (($ch & 192)==192) return(substr($str,0,$i));
  50:     }
  51:     return($str.$hex);
  52: }
  53:     //通过此添加此Hook以保证最新留言能够被缓存到options表中。
  54:     add_action('comment_post', 'cache_get_recent_comments');
  55:     add_action('edit_comment', 'cache_get_recent_comments');

上述代码只是个例子,仅仅提供了缓存最新留言的功能。这里将代码放上来,目的在于参考。拿来主义固然可以解决目前问题,自己动手方能巩固所学。Do It Yourself才是真正的乐趣。否则的话,玩转WP也就失去意义了。 

或许有些网友可能会说,做这些事情干什么?直接静态化不就可以了。通过直接生成实际的html文件固然有其好处,完全不需要php解析和数据库查询等,然后实际应用中,还需要解决一些问题,如一些互动信息,最新留言文章等,一旦静态化后,这部分内容就被定格了。再则,静态化插件很容易和一些下载插件存在兼容性问题,在点击这些下载插件生成的url时,很容易出现返回404错误。等等。

通过分析模板内容,我写了几个简单的函数将各页面中的通用部分缓存到数据库中,可以在一定程度上减少数据库查询次数。如原来这个模板首页需要36次查询,现在为25次。文章页为41次查询,现在为32次。当然,此法并非能解决所有问题,如文章页中的推荐阅读,因为推荐阅读涉及2个方面,一是和该post相关,也就是说要传递post id,在wp_options中给每个post id分个键值,显然是不可取的,二是推荐阅读的内容能自动和新发布文章挂钩。

实际上,我现在模板的数据库查询还是非常高的,主要是当时制作时根本就没有考虑这方面的影响。如果能在模板制作时,将数据库查询问题考虑进去,这样就能最大程度地减低查询数了。 

以上的东西能否制作成插件?答案是可以的。制作一个插件提供缓存的留言,文章,标签等功能的显示,乃至可以提供现有wp内置widget提供功能的缓存。然而这并非是我写此文的目的了。分享和探讨,这才是我的初衷。当然如果需要多了,写个插件也未尝不可。

p.s,关于插件制作,上次和牛人Askie瞎聊过这方面的事情。也没有整理,直接放上来。至于为何称此君为牛人呢,您说连Blog地址都是pkphp,能和php PK的人,能不牛乎?

me: 其实现在插件很多了。 

10:34 PM 写一些普通作用的插件也没什么意思的。关键是idea。

我挺欣赏你的那个加水印的插件

imaskie: 哈哈 

看见你的夸奖了

10:35 PM me: 要写就弄些有点新意的东西,要么就不要再去折腾普通的插件。

imaskie: 奥 

10:36 PM 人家有的就不去重复了

me: 弄普通的插件,这么浪费你这人才么,呵呵

imaskie: 哈哈 

me: 人家有的,再去弄,除非方法或效率方面有提高,否则有什么意思。你说呢。

imaskie: 是呀

10:37 PM me: 这就像转载人家文章似的。 

imaskie: 恩

看见你的博客里的内容了

都是原创 

很有技术

不错

me: 哎,谢谢夸奖啊。都是自己在瞎弄。 

10:38 PM 要不瞎弄,怎么玩wp。呵呵

其实坛子上很多朋友的问题,只需要他们自己动手测试下,大部分都可以自己解决的。

OK,到此结束,欢迎拍砖。 :)

Feed Me


转载文章请注明转载自:ThinkAgain - Let's Blog!

引用地址:http://www.thinkagain.cn/archives/969.html