簡単な質問です。
ループ内でPDO :: fetchAll()とPDO :: fetch()を使用するのにパフォーマンスの違いはありますか(結果セットが大きい場合)?
ユーザー定義クラスのオブジェクトにフェッチしていますが、違いがある場合はそれを取得しています。
Mydo_queryは1つしか実行できませんが、PDOは1つのステートメントで複数の操作を実行できるため、fetchAllの方が高速である可能性があります。しかし、私はPDOの内部動作についてほとんど知識がなく、ドキュメントではこれについて何も述べておらず、fetchAll()が単にPHP側のループが配列にダンプされているかどうかもわかりません。
助けがありますか?
20万個のランダムレコードを使用した小さなベンチマーク。予想どおり、fetchAllメソッドは高速ですが、より多くのメモリが必要です。
Result :
fetchAll : 0.35965991020203s, 100249408b
fetch : 0.39197015762329s, 440b
使用されたベンチマークコード:
<?php
// First benchmark : speed
$dbh = new PDO('mysql:dbname=testage;dbhost=localhost', 'root', '');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = 'SELECT * FROM test_table WHERE 1';
$stmt = $dbh->query($sql);
$data = array();
$start_all = microtime(true);
$data = $stmt->fetchAll();
$end_all = microtime(true);
$stmt = $dbh->query($sql);
$data = array();
$start_one = microtime(true);
while($data = $stmt->fetch()){}
$end_one = microtime(true);
// Second benchmark : memory usage
$stmt = $dbh->query($sql);
$data = array();
$memory_start_all = memory_get_usage();
$data = $stmt->fetchAll();
$memory_end_all = memory_get_usage();
$stmt = $dbh->query($sql);
$data = array();
$memory_end_one = 0;
$memory_start_one = memory_get_usage();
while($data = $stmt->fetch()){
$memory_end_one = max($memory_end_one, memory_get_usage());
}
echo 'Result : <br/>
fetchAll : ' . ($end_all - $start_all) . 's, ' . ($memory_end_all - $memory_start_all) . 'b<br/>
fetch : ' . ($end_one - $start_one) . 's, ' . ($memory_end_one - $memory_start_one) . 'b<br/>';
PHPについて、私がほぼ真であることがわかっていることの1つalwaysは、自分で実装する関数がPHPの同等の関数よりもほとんど常に遅いということです。これは、PHPに何かが実装されている場合、Cが持つすべてのコンパイル時最適化(PHPが記述されている)がなく、PHP関数呼び出しのオーバーヘッドが大きいためです。 。
「メモリフットプリント」を測定する上記のすべてのベンチマークは、非常に単純な理由で実際には正しくありません。
PDOはデフォルトですべてのものをメモリにロードし、fetchとfetchAllのどちらを使用してもかまいません。バッファなしクエリの利点を実際に得るには、PDOにバッファなしクエリを使用するように指示する必要があります。
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
その場合、スクリプトのメモリフットプリントに大きな違いが見られます。
@Arkh
// $data in this case is an array of rows;
$data = $stmt->fetchAll();
// $data in this case is just one row after each loop;
while($data = $stmt->fetch()){}
// Try using
$i = 0;
while($data[$i++] = $stmt->fetch()){}
メモリの違いは無視できるはずです
Mihai Stancuが言っていたように、fetchAllはfetch + whileに勝りますが、メモリの違いはほとんどありません。
Result :
fetchAll : 0.160676956177s, 118539304b
fetch : 0.121752023697s, 118544392b
私は正しく実行中に上記の結果を得ました:
$i = 0;
while($data[$i++] = $stmt->fetch()){
//
}
したがって、fetchAllはより少ないメモリを消費しますが、fetch + whileは高速です! :)
しかし、フェッチしたデータを配列に格納している場合、メモリ使用量は等しくなりますか?
<?php
define('DB_Host', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
// database to use
define('DB', 'test');
try
{
$dbh = new \PDO('mysql:dbname='. DB .';Host='. DB_Host, DB_USER, DB_PASS); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = 'SELECT * FROM users WHERE 1';
$stmt = $dbh->query($sql);
$data = array();
$start_all = microtime(true);
$data = $stmt->fetchAll();
$end_all = microtime(true);
$stmt = $dbh->query($sql);
$data = array();
$start_one = microtime(true);
while($data = $stmt->fetch()){}
$end_one = microtime(true);
// Second benchmark : memory usage
$stmt = $dbh->query($sql);
$data = array();
$memory_start_all = memory_get_usage();
$data = $stmt->fetchAll();
$memory_end_all = memory_get_usage();
$stmt = $dbh->query($sql);
$data = array();
$memory_end_one = 0;
$memory_start_one = memory_get_usage();
while($data[] = $stmt->fetch()){
$memory_end_one = max($memory_end_one, memory_get_usage());
}
echo 'Result : <br/>
fetchAll : ' . ($end_all - $start_all) . 's, ' . ($memory_end_all - $memory_start_all) . 'b<br/>
fetch : ' . ($end_one - $start_one) . 's, ' . ($memory_end_one - $memory_start_one) . 'b<br/>';
}
catch ( PDOException $e )
{
echo $e->getMessage();
}
?>
Result :
fetchAll : 2.6941299438477E-5s, 9824b
fetch : 1.5974044799805E-5s, 9824b
私はこれが古いトピックであることを知っていますが、同じ問題を抱えてこれに出くわします。私自身の単純な「ベンチマーク」を実行し、他の人がここに書いたものを読んで、これは正確な科学ではないという結論に達しました。プロジェクトの。
私の提案は、次のとおりです。コードをしばらく(ベータ版で)実行してデータを収集し、最適化を開始します。
簡単なベンチマーク(テストされた実行時間のみ)では、両方の方法で5%から50%の間で結果が変化しています。同じスクリプトで両方のオプションを実行しますが、最初にfetch +を実行すると、fetchallより高速で、その逆も同様です。 (私はそれらを1回実行し、数百回中央値と平均値を取得してから比較する必要があることを知っていますが、最初に言ったように、私はそれを始めるには早すぎると結論付けました。)