简体   繁体   English

Doctrine查询内存使用情况

[英]Doctrine query memory usage

Doctrine appears to be taking well over 4MB of RAM to execute a single, simple query: Doctrine似乎占用了超过4MB的RAM来执行一个简单的查询:

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

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

This is on a test database with very little data in it - the item that I am querying doesn't contain any data other than what is displayed here. 这是在一个测试数据库中,其中包含非常少的数据 - 我查询的项目不包含除此处显示的数据之外的任何数据。

Is there potentially something wrong with the way I have the system set up, or is this standard memory usage for Doctrine? 我的系统设置方式是否有可能出现问题,或者是Doctrine的标准内存使用情况?

From what I can see, you code doesn't seem to be wrong... 从我所看到的,你的代码似乎没有错...


As a test, I've set up a quick example, with a very simple table (only four fields) . 作为测试,我已经设置了一个快速示例,其中包含一个非常简单的表(只有四个字段)

Here is the relevant code : 这是相关代码:

var_dump(number_format(memory_get_peak_usage()));

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

var_dump(number_format(memory_get_peak_usage()));

When doing that, I have this kind of output : 这样做时,我有这种输出:

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

Considering the table is really simple and that I am only fetching one line, it seems "much" to me too -- but that's quite consistent with what you are getting, and with what I saw on other projects :-( 考虑到桌子非常简单,而且我只取一条线,对我来说似乎“很多” - 但这与你得到的结果非常一致,并且与我在其他项目中看到的一致:-(


If you only need to display your data, and not work with it (ie update/delete/...), a solution might be to not fetch complex objects, but only a simple array : 如果您只需要显示数据,而不是使用它(即更新/删除/ ...),解决方案可能不是获取复杂对象,而只是一个简单的数组:

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

But, in this case, it doesn't make much of a difference, actually :-( : 但是,在这种情况下,它并没有太大的区别,实际上:-(:

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

Only 40 KB of difference -- well, with bigger objects / more lines, it might still be a good idea... 只有40 KB的差异 - 好吧,更大的物体/更多的线条,它可能仍然是一个好主意...


In the Doctrine manual, there is a page called Improving Performance ; 在Doctrine手册中,有一个名为Improved Performance的页面; maybe it could help you, especially for these sections : 也许它可以帮助你,特别是对于这些部分:


Oh, btw : I did this test on PHP 5.3.0 ; 哦,顺便说一下:我在PHP 5.3.0上做过这个测试; maybe this can have an impact on the amount of memory used... 也许这会对使用的内存量产生影响......

I agree with romanb's answer - using an OpCode cache is a definite must when using large libs/frameworks. 我同意romanb的回答 - 使用大型库/框架时,使用OpCode缓存是必须的。

An example related to OpCode caching 与OpCode缓存相关的示例

I've recently adopted Doctrine usage with Zend Framework and was curious about memory usage - so like the OP, I created a method using similar criteria to the OPs test and ran it as an overall test to see what ZF + Doctrine's peak memory usage would be. 我最近采用了Zend Framework的Doctrine用法并且对内存使用感到好奇 - 所以和OP一样,我创建了一个使用类似OPs测试标准的方法,并将其作为一个整体测试运行,看看ZF + Doctrine的峰值内存使用量是多少是。

I got the following results: 我得到了以下结果:

Result without APC: 没有APC的结果:

10.25 megabytes
RV David
16.5 megabytes

Result with APC: APC的结果:

3 megabytes
RV David
4.25 megabytes

Opcode caching makes a very significant difference. 操作码缓存具有非常显着的差异。

Caution with fetchOne() on Doctrine Query. 在Doctrine Query上使用fetchOne()时要小心。 This function call will not append "Limit 1" on SQL 此函数调用不会在SQL上附加“限制1”

If you just need to get one records from DB, make sure: 如果您只需要从DB获取一条记录,请确保:

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

The memory usage is tremendous dropped on large table. 大表上的内存使用量大幅下降。

You could see fetchOne() will fetch from DB as a collection first then return the first element. 您可以看到fetchOne()将首先从DB获取作为集合,然后返回第一个元素。

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;
}

Well, where does this memory usage come from? 嗯,这个内存使用来自哪里? As Pascal MARTIN pointed out, array hydration does not make a great difference which is logical concerning that we're only talking about a few records here. 正如Pascal MARTIN指出的那样,阵列水合作用并没有产生很大的不同,这在逻辑上是因为我们在这里只讨论了一些记录。

The memory consumption comes from all the classes that are loaded on demand through autoloading. 内存消耗来自通过自动加载按需加载的所有类。

If you dont have APC set up, then yes, there is something wrong with the way your system is set up. 如果您没有设置APC,那么是的,您的系统设置方式有问题。 Dont even start to measure performance and expect good results with any large php library without an opcode cache like APC. 甚至不开始测量性能,并期望任何大型PHP库没有APC等操作码缓存的良好结果。 It will not only speed up the execution but also reduce memory usage by at least 50% on all page loads except the very first one (where APC needs to cache the bytecodes first). 它不仅可以加速执行,还可以在所有页面加载时减少至少50%的内存使用量,除了第一个(APC需要首先缓存字节码)。

And 4MB with your simple example really smells like no-APC, otherwise it would really be a bit high. 你的简单例子4MB真的闻起来像没有APC,否则它真的会有点高。

Doctrine provides a free() function on Doctrine_Record, Doctrine_Collection, and Doctrine_Query which eliminates the circular references on those objects, freeing them up for garbage collection. Doctrine在Doctrine_Record,Doctrine_Collection和Doctrine_Query上提供了一个free()函数,它消除了对这些对象的循环引用,将它们释放出来进行垃圾回收。 More info.. 更多信息..

To make memory usage a little bit less You can try to use folowing code: 使内存使用量少一些您可以尝试使用以下代码:

  • $record->free(true) – will do deep free-up's, calls free() on all relations too $ record-> free(true) - 将进行深度释放,对所有关系调用free()
  • $collection->free() – this will free all collection references $ collection-> free() - 这将释放所有集合引用
  • Doctrine_Manager::connection()->clean()/clear() – cleanup connection (and remove identity map entries) Doctrine_Manager :: connection() - > clean()/ clear() - 清理连接(并删除身份映射条目)
  • $query->free() $查询 - >免费()

I would guess that most of that memory is used up loading Doctrine's classes, not actually for objects associated with the query itself. 我猜大多数内存用于加载Doctrine的类,而不是用于与查询本身相关联的对象。

  • Which version of Doctrine are you using? 您使用的是哪个版本的Doctrine?
  • Are you using the autoloader? 你在使用自动加载器吗?

In Doctrine 1.1, the default autoload behavior is called 'aggressive', which means that it load all of your model classes even if you're only using one or two on any particular request. 在Doctrine 1.1中,默认的自动加载行为称为“激进”,即使您在任何特定请求中仅使用一个或两个,它也会加载所有模型类。 Setting that behavior to 'conservative' would reduce memory usage. 将该行为设置为“保守”将减少内存使用量。

我刚刚用symfony 1.4做了“daemonized”脚本并设置了以下内容停止了内存占用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM