PDO :: fetchAll vs. PDO :: выборка в цикле

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

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

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

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

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

Маленький тест с 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/>'; 

Одна вещь о 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()){} 

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

Как сказал Михай Станку, почти нет разницы в памяти, хотя 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 

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

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

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

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

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

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

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