【问题标题】:Doctrine query memory usage教义查询内存使用情况
【发布时间】:2009-09-11 19:09:29
【问题描述】:

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

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

这是一个测试数据库,其中的数据非常少 - 我正在查询的项目不包含除此处显示的数据之外的任何数据。

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

【问题讨论】:

    标签: php doctrine memory-management


    【解决方案1】:

    据我所知,您的代码似乎没有错...


    作为测试,我设置了一个简单的示例,其中包含一个非常简单的表格(只有四个字段)

    这里是相关代码:

    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 上做了这个测试;也许这会对使用的内存量产生影响......

    【讨论】:

    • 这让我很担心,因为我正在将 Doctrine 集成到我的框架中。
    • 在担心太多之前,您可能需要进行更多测试,使用更大的表、更多数据等等——看看内存增加是否是线性的。 ;;顺便说一句:我已经看到 Doctrine 在基于 Zend 框架和 Symfony 的项目中使用,这从来都不是问题......
    • Pascal MARTIN:也许您知道的这些网站负载不重?我想知道是否有任何主要网站正在使用 Doctrine。
    • 我通常将新项目锁定到 16MB 的内存限制。除了一个例外,我从来没有用过 Doctrine 的限制。此外,在首次使用 Doctrine 时,会启动大量内部引用变量和单例。
    • 现在可以在readthedocs.org/docs/doctrine/en/latest/en/manual/…找到1.2文档的链接
    【解决方案2】:

    我同意 romanb 的回答 - 在使用大型库/框架时,使用 OpCode 缓存是绝对必须的。

    与操作码缓存相关的示例

    我最近在 Zend Framework 中采用了 Doctrine,并且对内存使用情况感到好奇 - 所以和 OP 一样,我创建了一个使用与 OPs 测试类似的标准的方法,并将其作为一个整体测试运行,以查看 ZF + Doctrine 的峰值内存使用量会。

    我得到了以下结果:

    没有 APC 的结果:

    10.25 megabytes
    RV David
    16.5 megabytes
    

    APC 的结果:

    3 megabytes
    RV David
    4.25 megabytes
    

    操作码缓存有很大的不同。

    【讨论】:

      【解决方案3】:

      那么,内存使用量从何而来?正如 Pascal MARTIN 所指出的,阵列水合不会产生很大的影响,这在我们这里只讨论几条记录方面是合乎逻辑的。

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

      如果您没有设置 APC,那么是的,您的系统设置方式有问题。甚至不要开始测量性能并期望在没有像 APC 这样的操作码缓存的情况下使用任何大型 php 库的良好结果。除了第一个页面加载(APC 需要首先缓存字节码)之外,它不仅会加快执行速度,而且还会将所有页面加载的内存使用量减少至少 50%。

      您的简单示例中的 4MB 真的闻起来像没有 APC,否则它真的有点高。

      【讨论】:

        【解决方案4】:

        在 Doctrine Query 上使用 fetchOne() 时要小心。此函数调用不会在 SQL 上附加“限制 1”

        如果您只需要从数据库中获取一条记录,请确保:

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

        【讨论】:

          【解决方案5】:

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

          为了减少内存使用你可以尝试使用以下代码:

          • $record->free(true) - 将进行深度释放,也会在所有关系上调用 free()
          • $collection->free() - 这将释放所有集合引用
          • Doctrine_Manager::connection()->clean()/clear() – 清理连接(并删除身份映射条目)
          • $query->free()

          【讨论】:

            【解决方案6】:

            我猜大部分内存都用于加载 Doctrine 的类,而不是实际用于与查询本身关联的对象。

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

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

            【讨论】:

              【解决方案7】:

              我刚刚使用 symfony 1.4 完成了“守护进程”脚本,并设置以下内容停止了内存占用:

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

              【讨论】:

              • 如果您使用的是doctrine+symfony,这样做很好,但如果您只是使用Doctrine,则无济于事。
              • 同意 Ikon,在 symfony 中探查器 gobals ram。所以:sfConfig::set('sf_debug', false);BEFORE 如果像我一样将大表转储到 csv,那么建立数据库连接将非常有帮助。您可能希望在 frontend_dev.php 或类似(第 3 个参数)中执行此操作。
              猜你喜欢
              • 2016-08-05
              • 2021-06-19
              • 1970-01-01
              • 2015-04-03
              • 2015-10-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多