Doctrineクエリのメモリ使用量
-
06-07-2019 - |
質問
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のこの標準メモリ使用量ですか?
解決
私が見ることができるものから、あなたのコードは間違っていないようです...
テストとして、非常に単純なテーブル(4つのフィールドのみ)を使用した簡単な例をセットアップしました。
関連するコードは次のとおりです:
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)
表は非常にシンプルで、1行しかフェッチしていないと考えると、「かなり」と思われます。私にも-しかし、それはあなたが得ているものと、私が他のプロジェクトで見たものと非常に一致しています:-(
データを表示するだけで、それを操作する必要がない場合(つまり、更新/削除/ ...)、解決策は複雑なオブジェクトを取得せず、単純な配列のみを取得することです。
$test = Doctrine::getTable('Test')->find(1, Doctrine::HYDRATE_ARRAY);
しかし、この場合、実際には大きな違いはありません。実際には:-(:
string '1,316,424' (length=9)
string '2,107,128' (length=9)
わずか40 KBの違い-さて、より大きなオブジェクト/より多くの行があれば、それはまだ良い考えかもしれません...
Doctrineのマニュアルには、パフォーマンスの改善というページがありますa>;多分それは、特にこれらのセクションのためにあなたを助けることができます:
ああ、ところで:PHP 5.3.0でこのテストを行いました。多分これは、使用されるメモリの量に影響を与える可能性があります...
他のヒント
romanbの答えに同意します-大規模なlibs / frameworksを使用する場合、OpCodeキャッシュを使用することは絶対に必要です。
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
オペコードキャッシングは非常に大きな違いをもたらします。
さて、このメモリ使用量はどこから来たのですか? Pascal MARTINが指摘したように、配列のハイドレーションは大きな違いを生みません。これはここでいくつかのレコードについてのみ話しているということに関して論理的です。
メモリ消費は、自動ロードによってオンデマンドでロードされるすべてのクラスから発生します。
APCをセットアップしていない場合は、はい、システムのセットアップ方法に問題があります。 APCのようなオペコードキャッシュがなくても、パフォーマンスの測定を開始し、大きなPHPライブラリで良い結果を期待しないでください。実行を高速化するだけでなく、最初のページ(APCが最初にバイトコードをキャッシュする必要があるページ)を除くすべてのページロードでメモリ使用量を少なくとも50%削減します。
4MBの簡単な例では、APCなしのような匂いがします。そうでない場合は、実際には少し高くなります。
DoctrineクエリのfetchOne()に関する注意。この関数呼び出しは、「Limit 1」を追加しません; SQL
でDBからレコードを1つだけ取得する必要がある場合は、次のことを確認してください。
$q->limit(1)->fetchOne()
大きなテーブルでは、メモリ使用量が大幅に低下します。
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;
}
Doctrineは、Doctrine_Record、Doctrine_Collection、Doctrine_Queryでfree()関数を提供し、これらのオブジェクトの循環参照を削除し、ガベージコレクションに解放します。 詳細..
メモリ使用量を少し減らすには、次のコードを使用してみてください:
- $ record-&gt; free(true)&#8211;深い解放を行い、すべての関係でもfree()を呼び出します
- $ collection-&gt; free()&#8211;これにより、すべてのコレクション参照が解放されます
- Doctrine_Manager :: connection()-&gt; clean()/ clear()&#8211;接続のクリーンアップ(およびIDマップエントリの削除)
- $ query-&gt; free()
実際にはクエリ自体に関連付けられたオブジェクトではなく、Doctrineのクラスのロードにそのメモリの大部分が使用されていると思います。
- どのバージョンのDoctrineを使用していますか
- オートローダーを使用していますか?
Doctrine 1.1では、デフォルトの自動ロード動作は「アグレッシブ」と呼ばれ、特定のリクエストで1つまたは2つしか使用していない場合でもすべてのモデルクラスをロードします。その動作を「保守的」に設定すると、メモリ使用量が削減されます。
「デーモン化」したばかりです。 symfony 1.4でスクリプトを実行し、以下を設定するとメモリの占有が停止しました。
sfConfig::set('sf_debug', false);