2009-09-11 44 views
10

主义出现了4MB的内存是采取很好地执行一个单一的,简单的查询:主义查询内存使用

print memory_get_peak_usage()." <br>\n"; 
$q = Doctrine_Query::create() 
    ->from('Directories d') 
    ->where('d.DIRECTORY_ID = ?', 5); 

$dir = $q->fetchOne(); 
print $dir['name']." ".$dir['description']."<br>\n"; 

print memory_get_peak_usage()." <br>\n"; 

/*************** OUTPUT: ************************** 

6393616 
testname testdescription 
10999648 

/***************************************************/ 

这是一个试验数据库上,在它的数据非常少 - 我是项目查询不包含除此处显示的内容之外的任何数据。

有没有可能是我有系统设置的方式有问题,或者这是标准的内存使用原则?

回答

6

从我所看到的,你的代码似乎并没有错......


作为一个测试,我已经建立了一个简单的例子,有一个非常简单的表(只有四个字段)

下面是相关代码:

var_dump(number_format(memory_get_peak_usage())); 

$test = Doctrine::getTable('Test')->find(1); 

var_dump(number_format(memory_get_peak_usage())); 

如果这样做,我有这样的输出:

string '1,316,088' (length=9) 
string '2,148,760' (length=9) 

考虑到表是非常简单的,而且我只取一行这对我来说似乎“非常” - 但这与您所得到的以及我在其他项目中看到的相符: - (


如果你只需要显示您的数据,而不是与它的工作(即更新/删除/ ...),一个解决办法可能是不取复杂的对象,而只是一个简单的数组:

$test = Doctrine::getTable('Test')->find(1, Doctrine::HYDRATE_ARRAY); 

但在这种情况下,它没有多大的差别,实际上:-(:

string '1,316,424' (length=9) 
string '2,107,128' (length=9) 

只有40 KB的差异 - 好,有较大的对象/多行,它可能仍然是一个好主意...


在Doctrine手册中,有一个页面叫做Improving Performance;也许它可以帮助你,特别是对这些部分:


哦,顺便说一句:我做这个测试的PHP 5.3.0;也许这可能会影响内存使用量...

+0

这让我很担心,因为我正在将Doctrine融入到我的框架中。 – 2009-09-11 19:34:55

+0

在担心太多之前,您可能需要做更多的测试,包括更大的表格,更多的数据以及所有这些 - 以查看内存增加是否是线性的。 ;;顺便说一句:我已经看到基于Zend Framework和Symfony的项目中使用的学说,这从来没有成为一个问题... – 2009-09-11 19:38:26

+0

帕斯卡尔马丁:也许这些网站你知道没有重载?我想知道是否有任何主要网站正在使用Doctrine。 – Fragsworth 2009-09-11 21:36:13

4

那么,这种内存使用来自哪里呢?正如Pascal MARTIN指出的那样,阵列补水不会产生很大的差异,这是合乎逻辑的,因为我们只在这里讨论几条记录。

内存消耗来自所有通过自动加载按需加载的类。

如果您没有设置APC,那么是的,您的系统设置方式有问题。甚至不用像APC那样的操作码缓存,就可以开始衡量性能并期待任何大型php库的良好结果。它不仅会加快执行速度,还会减少所有页面负载(至少第一个APC需要首先缓存字节码)除外的内存占用至少50%。

而你的简单例子中的4MB确实闻起来像没有APC,否则它确实有点高。

5

我同意romanb的答案 - 使用OpCode缓存是使用大型库/框架时的必然要求。

我最近通过的原则使用与Zend框架,并很好奇内存使用相关指令缓存的一个例子 - 等等之类的OP,我创建使用类似的标准到OPS测试的方法和将其作为整体测试来查看ZF + Doctrine的峰值内存使用情况。

我得到以下结果:

的结果,而不APC:

10.25 megabytes 
RV David 
16.5 megabytes 

结果与APC:

3 megabytes 
RV David 
4.25 megabytes 

指令缓存让人十分显著差异。

2

Doctrine在Doctrine_Record,Doctrine_Collection和Doctrine_Query上提供了一个免费()函数,它消除了这些对象的循环引用,释放它们以进行垃圾回收。 More info..

为了使内存的使用情况有点少,你可以尝试使用如下因素代码:

  • $ record->免费(真) - 上都将做深腾出的,电话免费()关系太
  • $收藏 - >免费() - 这将释放所有集合引用
  • Doctrine_Manager ::连接() - >清理()/清除() - 清除连接(和删除标识映射条目)
  • $ query-> free()
1

我猜想大部分内存用于加载Doctrine的类,实际上并不适用于与查询本身相关的对象。

  • 您使用的是哪个版本的Doctrine?
  • 您是否使用自动装载机?

在Doctrine 1.1中,默认的自动加载行为被称为'积极',这意味着即使您只对任何特定请求使用一个或两个模型类,它也会加载所有模型类。将该行为设置为“保守”会减少内存使用量。

0

我刚才没有“进程化”在symfony 1.4和设置下面的脚本停止内存占用:)原则上查询

sfConfig::set('sf_debug', false); 
+0

如果您使用doctrine + symfony,但不会帮助,如果你只是使用Doctrine。 – 2011-01-02 19:49:02

+0

同意Ikon,在symfony中探测器gobals ram。所以:'sfConfig :: set('sf_debug',false);'** BEFORE **数据库连接将会非常缓慢,如果像我一样,将大表转储到csv。你可能想在* frontend_dev.php *或类似的(第三参数)中执行此操作。 – 2011-06-01 23:14:23

4

注意与fetchOne(。此函数调用不会追加“限制1”上的SQL

如果你只是需要从数据库得到一个记录,确保:

$q->limit(1)->fetchOne() 

内存占用率下降了巨大的大桌子。

你可以看到fetchOne()将首先作为集合从数据库中获取,然后返回第一个元素。

public function fetchOne($params = array(), $hydrationMode = null) 
{ 
    $collection = $this->execute($params, $hydrationMode); 

    if (is_scalar($collection)) { 
     return $collection; 
    } 

    if (count($collection) === 0) { 
     return false; 
    } 

    if ($collection instanceof Doctrine_Collection) { 
     return $collection->getFirst(); 
    } else if (is_array($collection)) { 
     return array_shift($collection); 
    } 

    return false; 
}