PDO :: fetchAll vs. PDO :: выборка в цикле - PullRequest
68 голосов
/ 05 мая 2010

Просто быстрый вопрос.

Есть ли разница в производительности между использованием PDO :: fetchAll () и PDO :: fetch () в цикле (для больших наборов результатов)?

Я выбираю объекты пользовательского класса, если это имеет какое-либо значение.

Мое первоначальное необразованное предположение состояло в том, что fetchAll может быть быстрее, поскольку PDO может выполнять несколько операций в одном операторе, а mysql_query может выполнять только одну. Однако я мало знаю о внутренней работе PDO, и документация ничего не говорит об этом, а также о том, является ли fetchAll () просто циклом на стороне PHP, выгруженным в массив.

Любая помощь?

Ответы [ 7 ]

74 голосов
/ 05 мая 2010

Маленький тест с 200k случайных записей. Как и ожидалось, метод 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/>';
10 голосов
/ 05 мая 2010

Одна вещь о PHP, которую я нахожу правдой почти всегда , заключается в том, что функция, которую вы реализуете самостоятельно, почти всегда будет медленнее, чем эквивалент PHP. Это происходит потому, что когда что-то реализовано в PHP, оно не имеет всех оптимизаций времени компиляции, которые есть у C (на которых написан PHP), и возникают большие накладные расходы на вызовы функций PHP.

9 голосов
/ 01 марта 2017

все тесты выше, которые измеряют «объем памяти», на самом деле неверны по очень простой причине.

PDO по умолчанию загружает все вещи в память и не заботится, используете ли вы fetch или fetchAll. Чтобы действительно получить преимущества небуферизованного запроса, вы должны указать PDO использовать небуферизованные запросы:

$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

В этом случае вы увидите огромную разницу в занимаемой памяти сценария

9 голосов
/ 03 июня 2010

@ Арх

// $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()){}

Разница в памяти должна стать незначительной

4 голосов
/ 25 декабря 2010

Как говорил Михай Станку, разницы в памяти почти нет, хотя fetchAll превосходит fetch + while.

Result : 
fetchAll : 0.160676956177s, 118539304b
fetch : 0.121752023697s, 118544392b

Я получил результаты выше с запуском в то время как правильно:

$i = 0;
while($data[$i++] = $stmt->fetch()){
    //
}

Таким образом fetchAll потребляет меньше памяти, но fetch + пока быстрее! :)

3 голосов
/ 28 мая 2012

Но наверняка, если вы храните извлеченные данные в массиве, использование памяти будет равно?

<?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
1 голос
/ 03 мая 2012

Я знаю, что это старая тема, но я сталкиваюсь с тем же вопросом. Проведя свой собственный простой «тест» и прочитав то, что здесь написали другие, я пришел к выводу, что это не точная наука, и хотя нужно стремиться писать качественный, легкий код, нет смысла тратить слишком много времени на старте проекта.

Мое предложение: собрать данные, запустив код (в бета-версии?) Некоторое время, а затем начать оптимизацию.

В моем простом тесте (только проверенное время выполнения) я получил результаты, варьирующиеся от 5% до 50% ОБА. Я запускаю обе опции в одном и том же скрипте, но когда я запускаю fetch +, сначала он был быстрее, чем fetchall, и наоборот. (Я знаю, что я должен был запустить их один и пару сотен раз, получить медиану и среднее, а затем сравнить, но - как я уже сказал в начале - я пришел к выводу, что в моем случае слишком рано начинать это делать.) *

...