3

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

方法:

理论:

我认为最好有一个类属性(变量)来存储获取的数据库数据,以防止需要重复将返回相同数据的查询或查询。

如果你不明白,这是我博客中的一个例子:


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

class FBuser
{

}

此类将包含的明显方法:

getStatusUpdates()
getAccountInfo()
getFriendIDs()

最初,这些方法都必须执行数据库查询,以获取所需的数据。但是使用缓存方法,我会定义一个类属性来存储缓存的数据,并且所有数据库查询都在一个方法中进行:

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

}

这样,我可以getData( 'the data I want' , true );在我想从数据库中获取数据时调用,允许我在可能的地方和时间使用缓存的数据。

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


4

2 回答 2

3

为什么这是个坏主意?

严格来说,这本身并不是一个坏主意,因为它会按照您的预期去做,并且如果您的脚本中有重复的查询,您可以获得一点性能。

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

实现一个持久缓存,一个存在于请求之间的缓存,是潜在的性能大奖所在,具体取决于您的应用程序/脚本。

我不是说“不要这样做”,我只是说除非您计划在同一个请求/脚本中运行相同的查询数百次,这通常不太可能,否则您不会看到太多没有持久的解决方案;但绝对不会受伤。

于 2012-08-28T03:49:40.570 回答
1

你的老师很傻:p

我要说的主要一点是,这种类型的缓存,取决于上下文,实际上非常有帮助。我在我开发的 web 框架中做了一些,这种重构是通过使用 XDebug 仔细分析缓存研磨驱动的。

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

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

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

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

保持绿色,每个周期都很重要:)

于 2012-08-27T22:58:41.840 回答