在Drupal中创建复杂的、动态的内容是很easy的,但需要做出一定的牺牲的。现在很多Web 2.0的特性的加入,使得网站在变得很cool的同时,也坠入了“性能恶梦(performance nightmare)”的深渊中。每一个节点的加载或一个页面的加载,都会引起高负载、大量的数据库访问、复杂的计算和大量的客户端脚本的执行。
一个解决方案是在Drupal的管理界面开启页面缓存。这个可以使匿名用户(即不登录的情况下)访问速度增加,因为Drupal会把每一个要输出的页面预先缓存(请注意!不是缓存成HTML页面,而是把整个页面的HTML内容序列化为字符串,然后存入数据库),这样可以大大的减少数据库的查询次数。但是,这个对于登录的用户是没有任何效果的:因为页面级的缓存是一种”要么全是要么就一点都没有(all-or-nothing)”的缓存方式,它只有在很标准的情况下才有效,并且所有用户看到的视图都是一样的。
不过,早晚有一天你需要挖掘你的代码,找出数据库的查询访问热点(hot spots),然后自己对程序进行缓存。幸运的是(我最喜欢看到Fortunately这个单词),Drupal有一些内建的关于缓存的API和一些指导性的文档,使得我们可以很easy的自定义Drupal程序的缓存。
基础
做优化和缓存的第一条(The first rule)就是:永远不要使消耗时间的操作执行两次!要充分利用第一次执行的结果,并重用它们(Never do something time consuming twice if you can hold onto the results and re-use them.)下面我们看一个简单的示例:
function my_module_function($reset = FALSE) {
static $my_data;
if (!isset($my_data) || $reset) {
// 在些进行复杂的计算,并使用正确的内容生成$my_data变量
}
return $my_data;
}
这段代码中最重要的部分,就是这个函数创建了一个静态变量——$my_data.静态变量的好处在于,当其第一次被赋值后,就可以被持续的使用,即使这个函数被重新调用。也就是说,我们先检查这个变量是否被赋值,如果已经有值了,那就不需要重新计算,只需要直接返回其值即可。
这种模式经常在Drupal中使用——其中包括很多关键的函数,如node_load。这个函数在被第一次调用时,根据传入的节点ID,查询数据库得到节点对像,并赋值于一个静态变量;然后如果这个节点再在一个Block中被调用,或被列表中调用,就不会再次查询数据库了。
另一个重要的特性是使用$reset参数。缓存确实很好,但偶尔你也需要确保用户访问的页面所得到的数据是绝对新鲜的(absolute freshest)。这时$reset变量就派上用场了。我们可以在需要更新缓存的时候,将$reset设置为TRUE。
Drpual的缓存函数
你可能注意到,静态变量只能在一个单独的页面生存周期内有效。如果需要更好的性能,我们可以使缓存的数据更持久……
function my_module_function($reset = FALSE) {
static $my_data;
if [...]