2011-08-31 4 views
12

Я использовал для получения большого объема данных с помощью mysql_query, а затем итерации по результату один за другим для обработки данных. Пример:В PHP, что происходит в памяти, когда мы используем 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 должен будет поместить результат в память в любом случае. Я хотел бы получить мнение того, кто понимает, что речь идет о производительности. Пожалуйста, не комментируйте код, я только что сделал его примером для публикации.

Благодаря

+0

Почему бы не попробовать их сами? –

+2

Для сравнения, посмотрите http://www.php.net/manual/en/function.mysql-unbuffered-query.php. – deceze

ответ

1

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

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

+0

Ein Link zur Englischen MySQL Dokumentation wäre glaube ich angebrachter. : o) – deceze

+0

Oups, извините, стимул. Я изменил его сейчас, поэтому все вы можете извлечь из этого выгоду :-) – glglgl

+0

Изменение данных между = ОЧЕНЬ хорошая точка! – U0001

-2

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

+4

OMG foreach быстрее, чем некоторое время –

+0

Да, имея дело с большими массивами данных, используйте 'foreach', когда это возможно, вместо циклов' while'. http://juliusbeckmann.de/blog/php-foreach-vs-while-vs-for-the-loop-battle.html это было доказано снова и снова ... – SoLoGHoST

+3

вопрос не о foreach vs while. И такое сравнение бесполезно: вы выполняете SQL-запрос 12sec, но вы пытаетесь оптимизировать цикл 0,1 с ... –

4

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

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

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

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

+0

Спасибо, полковник Шрапнель. Re: Эхо, это просто пример для иллюстрации. – U0001

2

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

$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"; 
    } 
} 

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

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

+0

Почему бы не сделать только один цикл? –

+0

Да, я мог бы проверить себя, но я ленив. И мне еще более любопытно мнение о нем. Например, некоторые люди здесь представили разные подходы и объяснили их. Это, для меня, лучше, чем тест. – U0001

Смежные вопросы