PDO:: fetchAll vs. PDO:: выборка в цикле
Просто быстрый вопрос.
Есть ли разница в производительности между использованием PDO:: fetchAll() и PDO:: fetch() в цикле (для больших наборов результатов)?
Я собираюсь в объекты пользовательского класса, если это имеет значение.
Мое первоначальное необразованное предположение заключалось в том, что fetchAll может быть быстрее, потому что PDO может выполнять несколько операций в одном из операторов, в то время как mysql_query может выполнять только один. Однако я мало осведомлен о внутренней работе PDO, и в документации ничего не сказано об этом, и является ли fetchAll() просто петля на стороне PHP, сбрасываемая в массив.
Любая помощь?
Ответы
Ответ 1
Маленький тест с 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/>';
Ответ 2
Одна вещь о PHP, которую я считаю правдой почти всегда, заключается в том, что функция, которую вы реализуете самостоятельно, почти всегда будет медленнее, чем эквивалент PHP. Это связано с тем, что, когда что-то реализуется в PHP, у него нет всех оптимизаций времени компиляции, которые имеет C (на котором написан PHP), и есть высокие накладные расходы на вызовы функций PHP.
Ответ 3
@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()){}
Разница в памяти должна стать нечитаемой
Ответ 4
Как сказал Михай Станку, разница в памяти практически отсутствует, хотя fetchAll бьет fetch + while.
Result :
fetchAll : 0.160676956177s, 118539304b
fetch : 0.121752023697s, 118544392b
Я получил приведенные выше результаты с правильной работой:
$i = 0;
while($data[$i++] = $stmt->fetch()){
//
}
Итак, fetchAll потребляет меньше памяти, но fetch + while быстрее!:)
Ответ 5
Но, конечно, если вы сохраняете извлеченные данные в массиве, использование памяти будет равным?
<?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
Ответ 6
все контрольные показатели, выше которых измеряют "объем памяти", фактически являются неправильными по самой простой причине.
PDO по умолчанию загружает все вещи в память, и все равно, если вы используете fetch или fetchAll.
Чтобы действительно получить преимущества небуферизованного запроса, вы должны проинструктировать PDO использовать небуферизованные запросы:
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
В этом случае вы увидите огромную разницу в объеме памяти script
Ответ 7
Я знаю, что это старая тема, но я сталкиваюсь с этим тем же вопросом. Запустив мой простой "тест" и прочитав то, что там написали другие, я пришел к выводу, что это не точная наука, и хотя нужно стремиться писать качественный, легкий код, нет смысла тратить слишком много времени в начале проекта.
Мое предложение: собрать данные, запустив код (в бета?) какое-то время, а затем начните оптимизацию.
В моем простом тестировании (только проверенное время выполнения) у меня есть результаты, варьирующиеся от 5% до 50%. Я запускаю оба параметра в том же script, но когда я запускаю fetch +, сначала он быстрее, чем fetchall и наоборот. (Я знаю, что я должен был запустить их один и пару сто раз получить медианную и среднюю, а затем сравнить, но, как я уже сказал в начале, я пришел к выводу, что в моем случае еще рано начинать делать это.)