Подтвердить что ты не робот

В PHP, что происходит в памяти, когда мы используем mysql_query

Я использовал для получения большого объема данных с помощью mysql_query, а затем итерации по результату один за другим для обработки данных. Пример:

$mysql_result = mysql_query("select * from user");
while($row = mysql_fetch_array($mysql_result)){
    echo $row['email'] . "\n";
}

Недавно я просмотрел несколько фреймворков и понял, что они извлекли все данные в массив в памяти и вернули массив.

$large_array = $db->fetchAll("select * from user");
foreach($large_array as $user){
    echo $user['email'] . "\n";
}

Я хотел бы знать плюсы и минусы каждого метода. Мне кажется, что загрузка всего в память - это рецепт катастрофы, если у вас очень длинный список предметов. Но опять же коллега сказал мне, что драйвер mysql должен будет поместить результат в память в любом случае. Я хотел бы получить мнение того, кто понимает, что речь идет о производительности. Пожалуйста, не комментируйте код, я просто сделал это в качестве примера для публикации.

Спасибо

4b9b3361

Ответ 1

Верно, что библиотека MySQL "обычно" извлекает все данные в клиентской памяти. Обычно это делается с помощью mysql_store_result(). Вы можете разделить слишком большие запросы, как показано выше, с ключевым словом LIMIT, но существует риск того, что данные будут несовместимы, поскольку они могут измениться между ними. Вы можете позаботиться об этом с помощью блокировок.

Другой подход может заключаться в использовании mysql_use_result(), который использует больше ресурсов на серверной стороне и требует завершения задания на выборка как можно скорее.

Ответ 2

вы смешиваете вопросы.

  • что делает ваш код WAY более плавным с массивами
  • и неоптимизированный алгоритм, когда неискушенный программист имеет тенденцию загружать ВСЕ данные в script вместо того, чтобы делать базу данных для выполнения всех вычислений или получения данных по частям.

Итак. Рамки не извлекают все данные. Они приносят именно то, что написал программист.
Таким образом, хороший программист не будет получать большие объемы данных в массив. В этих немногих случаях, когда это действительно необходимо, можно использовать старую поэтапную выборку (и каждая инфраструктура предоставляет метод для этого). Во всех остальных случаях следует использовать плавную выборку уже в массиве.

Также обратите внимание, что фреймворки никогда не будут делать такие вещи, как эхо-данные прямо внутри цикла базы данных.
Каждая хорошая структура будет использовать шаблон для вывода вещей, и в этом случае массив очень удобен.

Ответ 3

При работе с большими результирующими наборами я обычно просматриваю партии, например:

$current = 0;
$batchSize = 1000;

while (true) {
  $large_array = $db->fetchAll(sprintf("select * from user limit %s, %s", $current, $batchSize));
  if (sizeof($large_array) == 0) {
    break;
  }

  $current += sizeof($large_array);
  foreach($large_array as $user){
    echo $user['email'] . "\n";
  } 
}

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

Кстати, относительно легко проверить это самостоятельно, установив script, который измеряет время (и максимальную память) обоих фрагментов. Я бы сказал, что они не будут сильно отличаться во времени.

Ответ 4

Просто я узнал, когда дело доходит до производительности: foreach быстрее, чем цикл while. Возможно, вам следует оценивать результаты каждого из них и видеть, какой из них быстрее и меньше памяти. ИМХО, мне нравится, что последний подход лучше. Но действительно ли вам нужен каждый столбец внутри таблицы пользователя? Если нет, просто определите нужные столбцы вместо использования *, чтобы захватить их все. Так как это также поможет с памятью и скоростью.