各种系统开发中都会大量的使用缓存,用于提高程序执行速度,避免过于频繁的查询或者是过于复杂的查询的性能消耗。例如网站名称这样的设置项,每个页 面都会调用到,这属于频繁查询。另外一种比如是一个连接了3,4个表的sql查询,每次查询都会造成很大的数据库消耗,这属于复杂查询。
supesite中的缓存类型
supesite中有2种缓存,一种是文件缓存,一种是数据库缓存。
文件缓存的做法就是执行一次查询,然后将返回的结果生成一个.php的缓存文件,可以直接在程序中include进来,所有需要的地方都是直接include,这样就减少了数据库的查询。(当然,这里眼尖的同学会说这个增加了磁盘IO,等会下说个权衡问题)
数据库缓存的做法是将查询结果,再序列化成字符串,保存到数据库,碰到相同条件的查询语句时候,直接将查询结果又从数据库中读取出来。这里有些同学 不理解,既然是减少数据库查询的负担,为什么又把结果保存到数据库再读出来? 这是我们刚刚提到的复杂查询的缓存。我们将复杂的,性能消耗很高的查询结果保存到数据库,下次碰到一样的查询语句的时候,直接取出来,消耗仅仅是一个最简 单的select语句而已,可以完全避免复杂sql的性能消耗。
以上是2种缓存文件实现提高性能的方式。具体缓存机制如何实现呢?
缓存机制的实现
无论文件缓存还是数据库缓存,实现都包括3个方面:
生成,更新,调用。
文件缓存的生成
文件缓存较为简单。生成文件缓存,只要将数据库结果整理成字符串,然后应用php自带的fwrite()函数将字符串写入文件即可。当然也要注意生成的文件语法要正确,才可以保证include的时候不会出错。
supesite中生成缓存的代码:
其中$tarr是结果集数据组,指定文件名,生成文件就行.arrayeval是supesite中转换数据为缓存内容的函数,具体如下:
writefile是supesite封装的一个写文件的函数。主要是保证生成的php文件不会存在语法出错的状况,并且增加一定的可读性。
文件缓存的更新
文件缓存的更新,就涉及到了整个业务机制了。有两种更新需求,一种是即时更新,就是一旦结果集发生变化,缓存文件也要更新,适应于对实时性要求比较 高的配置项。另一种是定时更新,每隔一段时间就检查是否到了更新的时间点,到了时间点之后,无论结果是否有变化,都执行更新。不过两种方式没有绝对的性能 优劣。假设结果集更新非常频繁,那么显然定时更新的方式性能较优,但是如果结果集很久才变化一次,那么即时更新的方式更划算。
即时更新的实现难度不大,只要在更新结果集的时候同时更新缓存即可。比如系统修改了设置项,那么在执行完数据库修改语句后,再加上缓存文件的更新代码即可。
定时更新则会稍微有一点点麻烦,你需要一个配置项来记住当前文件更新的时间间隔(例如1小时),然后每次触发执行的时候,都判断下当前时间与文件时间的差异是否达到了更新的间隔。
文件缓存的调用
文件缓存的调用非常简单,php中只要include指定的文件就可以了。当然,要稍微注意下include,require,include_once,require_once的差异。一般可使用include_once。
数据库缓存的实现
数据库缓存的整体实现机制相比文件缓存来说复杂得多,需要一整套完整的从生成更新到调用的机制。
supesite中采用的机制叫block,中文应该叫簇。这是一个相当好的设计,它极大的简化了数据调用的方式,并且与数据库缓存机制紧密结合,目前这种机制在各种开源CMS中都很流行。
首先来看看整套缓存表的设计,整个建表语句如下:
show create table supe_cache;
cachekey缓存主键,用于识别缓存,uid基本是无用,可以忽略。cachename是supesite中区分缓存的内容的类型的,例如分类 调用缓存,新闻调用缓存,评论调用缓存等,通过cachename字段,可以允许后台单独对某些分类的缓存进行更新。value则是整个调用结果集,它是 php中的结果数组的序列化字符串。updatetime记录的是下次缓存要更新的时间。
通过这个设计,可以得出整个数据库缓存的实现思路:生成缓存的时候,生成一个唯一的cachekey作为主键,将结果集序列化为数组保存在数据库 中,并记录下次更新的时间。调用缓存的时候凭借cachekey主键获取,并判断updatetime时间是否已经到达更新的时间点,如果需要更新,则更 新缓存表。否则直接读取缓存的结果集。
这里面围绕着一个核心的技术问题:
如何将sql调用跟唯一的cachekey对应起来?也就是说我执行一条sql语句来查询数据,这个查询怎么生成一个唯一的cachekey,然后我下次再次执行同样的sql就可以跟通过cachekey找到缓存结果?
这里就是supesite的核心函数block的功劳了。
FROM:http://www.fangyuqiang.com/archives/1025