使用类属性缓存数据——为什么这是个坏主意


Caching data with class properties - why is it a bad idea?

我最近读了很多关于PHP应用程序可伸缩性的文章。我读过的几乎所有文章都提到了缓存,所以我提出了在类属性中缓存DB数据的想法,以防止过多的DB查询。我想分享这个想法,所以我在博客上写了这个想法,结果老师告诉我这毫无意义,很愚蠢。除了使用毫无意义和愚蠢的词语外,他无法真正解释为什么它很糟糕。这里有人能解释一下为什么这种帮助扩展PHP应用程序的缓存方法不好吗?

方法:

理论:

我认为最好有一个类属性(变量)来存储提取的DB数据,以防止需要重复的查询或返回相同数据的查询,而不是从DB中提取每个方法中的数据(在需要的地方),执行一个又一个查询。

如果你不明白,这里有一个来自我博客的例子:


我将把Facebook引入这个例子中,只是为了稍微简化一下解释。假设我们正在为社交网络重新编码用户类。

class FBuser
{
}

这个类将包含的明显方法:

getStatusUpdates()
getAccountInfo()
getFriendIDs()

最初,这些方法都必须执行数据库查询,才能获得所需的数据。但是使用缓存方法,我将定义一个类属性来存储缓存的数据,并将所有DB查询都用一个方法进行:

class FBuser
{
    private $userCache = array();
    private function getData( $dataToGet = '' )
    {
    //all of my db querying would happen here
    }
}

但在同样的方法中,如果允许的话,我也会寻找缓存:

private function getData( $dataToGet = '' , $useCache = true )
{
   //am I allowed to use cache?
   if ( $useCache === true )
   { 
       //does the appropriate data exist in cache?
       if ( isset($this->userCache[ $dataToGet ]) )
       {
           return $this->userCache[ $dataToGet ];//return the cached data, and forget about the DB queries
       }
   }
   //if we get here, caching was disabled or the required data has not yet been cached :(
   //all of my db querying would happen here
   //store the data that's just been fetched by the queries in the cache property
}

这样,每当我想从DB中获取数据时,我都可以调用getData( 'the data I want' , true );,从而允许我在可能的情况下使用缓存的数据。

因此,如果我需要多次调用getAccountInfo()getStatusUpdates()getFriendIDs(),这种方法将阻止执行多个DB查询=有利于扩展(我认为)。


为什么这是个坏主意?

严格地说,这本身并不是一个坏主意,因为它会做你期望它做的事情,并且如果你的脚本中有重复的查询,会有一点性能提升。

然而,在实践中,除非你的脚本正在做一些非常好的事情,不寻常的,否则典型的PHP脚本的每个请求的数据库调用次数不会超过15或20次,其中可能只有2或3次是重复的顶部。如果数据库调用已经相对较快,那么haxing 2或3个数据库调用的性能差异将可忽略不计。更不用说数据库本身可能已经有了缓存系统!

根据您的应用程序/脚本,实现持久缓存(存在于请求之间)是潜在的性能大奖所在。

我并不是说"不要这么做",我只是说,除非您计划在同一请求/脚本中运行数百次同一查询,否则如果没有持久的解决方案,您将看不到太多结果;但这绝对不会有什么害处。

你的老师很傻:p

我想说的主要一点是,根据上下文的不同,这种类型的缓存实际上非常有用。我在我开发的web框架中做了一些这方面的工作,这种重构是由使用XDebug对cachegrinds的仔细分析驱动的。

这样想吧。数据库访问是PHP脚本将执行的最昂贵的工作(就性能而言)。很容易找到与DB相关的调用占页面总执行时间50%(或更多)的页面。为什么不缓存结果,这样数据的任何重用都会自动受益?

在PHP资源分配方面,没有理由不这样做,因为在封面下,PHP将共享对zval的引用,除非它们被修改,所以你的脚本也不需要堆上更多的内存。

对于那些对此表示怀疑的人,我会挑战他们在一个只调用一个DB而不是两个DB的页面上运行XDebug,并向全世界宣布他们看不到显著的结果。当实现这一点的代码如此简单时,为什么不进行改进呢?

现在,有些人可能会指出更持久的缓存形式,并说你应该使用它们来代替它。我不同意这种回应所隐含的普遍性。也许该数据集太大,无法在服务器上整体缓存。例如,当每天只有1%的用户登录时,我不会将每个人的数据都缓存在内存中。服务器上的内存不值得。也许数据会频繁更新,在这种情况下,同步会成为一个问题/负担,可能会超过缓存的好处。我想说的是,在某些情况下,更持久的缓存形式是不合适的。

绿色,每个循环计数:)