PDO :: fetchAll与PDO ::在循环中获取
只是一个简单的问题。
在循环(对于大型结果集)中使用PDO :: fetchAll()和PDO :: fetch()之间是否有任何性能差异?
如果这样做有什么区别的话,我可以获取用户定义的类的对象。
我最初没受过教育的假设是fetchAll可能会更快,因为PDO可以在一个语句中执行多个操作,而mysql_query只能执行一个。 然而,我对PDO的内部工作知之甚less,文档也没有提到这个问题,fetchAll()是不是只是一个PHP端的循环转储到数组中。
任何帮助?
与200k随机logging的小基准。 正如所料,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的一件事,我发现几乎总是这样的:你自己实现的函数几乎总是比PHP等价。 这是因为当在PHP中实现某些东西时,它没有完成C所有的编译时优化(PHP被写入),PHP函数调用的开销也很高。
@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所说的那样,尽pipefetchAll比fetch +要快,但几乎没有任何记忆差异。
Result : fetchAll : 0.160676956177s, 118539304b fetch : 0.121752023697s, 118544392b
我正确地运行了上面的结果:
$i = 0; while($data[$i++] = $stmt->fetch()){ // }
所以fetchAll消耗更less的内存,但获取更快的速度! 🙂
但是,当然,如果你将获取的数据存储在一个数组中,内存的使用情况是否相等?
<?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
所有测量“内存占用”的基准实际上是不正确的,原因很简单。
PDO在默认情况下会将所有内容加载到内存中,并且不会在意使用fetch或fetchAll。 要真正获得未缓冲的查询的好处,您应该指示PDO使用未缓冲的查询:
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
在这种情况下,您将看到脚本内存占用量的巨大差异
我知道这是一个古老的话题,但我遇到了同样的问题。 通过运行我自己的简单的“基准”并阅读别人在这里写的内容,我得出的结论是,这不是一门精确的科学,而应该努力写出质量轻的代码,没有任何一点浪费太多的时间在开始的项目。
我的build议是:通过运行代码收集数据(在beta?)一段时间,然后开始优化。
在我简单的基准testing中(只testing执行时间),我得到的结果变化在5%到50%之间。 我在同一个脚本中运行这两个选项,但是当我首先运行fetch +时,它比fetchall快,反之亦然。 (我知道我应该让他们单身,几百次得到中位数和平均数,然后再比较,但是 – 正如我在开始时所说的那样 – 我的结论是,现在开始这样做还为时过早。