mysqli_free_result()

topol

Новичок
Здравствуйте!
Хотел бы предупредить, я не программист. Возможно, мои вопросы покажется нелепыми.

В документации сказано, что для очистки памяти от результата запроса необходимо выполнить mysqli_free_result()

Также в документации сказано:
Освобождение ресурсов

Благодаря системе подсчета ссылок, введенной в PHP 4 Zend Engine, определение отсутствия ссылок на ресурс происходит автоматически, после чего он освобождается сборщиком мусора. Поэтому, очень редко требуется освобождать память вручную.
Вопрос 1:
Правильно ли, я понимаю, что если я перезапишу или уничтожу переменную содержащую результат запроса, память освободится автоматически?

Вопрос 2:
Если я сразу считываю данные из результата, не создавая промежуточную переменную, освобождается ля память автоматически?
Примеры:
PHP:
$a = $db->query('SELECT * FROM `t1` LIMIT 0, 1')->fetch_assoc();
$b = $db->query('SELECT * FROM `t1` LIMIT 0, 10')->fetch_all();
Получаем сразу массивы с данными.
Т.е. mysqli_free_result() мы уже не сможем ни к чему применить.

Для проверки своих суждений сделал тест:
Из таблицы, содержащей 3 млн. строк (~1 ГБ), выбирал поочередно все данные:

PHP:
for($i=0;$i<3000000;$i++) {
	$a = $db->query('SELECT * FROM `t1` LIMIT ' . $i . ', 1')->fetch_assoc();	//	сразу возвращает результат в виде массива
	$result = $db->query('SELECT * FROM `t1` LIMIT ' . $i . ', 1');	//	$result будет перезаписана при следующей итерации
}
Через top наблюдал за потреблением памяти. В результате работы скрипта, потребление памяти процессом не изменялось.


Вопрос 3:
Если мои суждения верны, тогда зачем выполнять $result->free(), если можно написать $result = 0, либо вообще ни чего не писать, если переменная $result будет перезаписана в другом запросе?

Вопрос 4:
Почему, во всех примерах, результат записывают в промежуточную переменную
PHP:
$result = $db->query('SELECT * FROM `t1` LIMIT 0, 1');
$a = $result->fetch_assoc();
$result->free();
когда можно можно написать сразу
PHP:
$a = $db->query('SELECT * FROM `t1` LIMIT 0, 1')->fetch_assoc();

Заранее, спасибо, за ответ.
 

WMix

герр M:)ller
Партнер клуба
самое важное понимать, где идет отчистка памяти, а в остальном ты прав,
Почему, во всех примерах, результат записывают в промежуточную переменную
mysqli_num_rows
 

Фанат

oncle terrible
Команда форума
уж больно у тебя вопросы заковыристые для непрограммиста
не видел ты непрограммистов, скажу я тебе. жизни не видел, портянок не нюхал.
жизнь - она вот она, вокруг:
я припомнил очевидную вещь, цикл выдает только последний результат.
если твой вопрос - от непрограммиста, то вот это ^^^ от кого?
Вопрос 1:
Правильно ли, я понимаю, что если я перезапишу или уничтожу переменную содержащую результат запроса, память освободится автоматически?
Не совсем.
А точнее, есть нюанс.
Насколько я помню политику партии, память, занимаемая скриптом, не освобождается всё равно.
Если отожрала переменная 100 метров, а потом обнулилась, то внутри скрипта эта память используется повторно, но вот наружу освобождённая память не ушла. Освободится только с завершением скрипта.
Я думаю, ты своим тестом легко это проверишь.
Вопрос 2:
Если я сразу считываю данные из результата, не создавая промежуточную переменную, освобождается, ля, память автоматически?
Забыл выделить вводное слово запятыми.
В контексте вышесказанного - да.
Вопрос 3:
Если мои суждения верны, тогда зачем выполнять $result->free(),
Во-первых, никто и не говорит, что нужно. Наоборот - везде пишут, что освобождать ресурсы и закрывать файлы и соединения не обязательно - все украдут после нас. В документации пишут, я имею в виду.
Если же говорить о кодах, то
- во-первых, есть такое понятие, как "good practice". Считается хорошей практикой освобождать ресурс, когда он тебе больше не нужен.
- во-вторых, есть такое понятие, как копипаста. 99.9% программистов, пишущих на похапе, бесполезно спрашивать о том, почему они написали или не написали тот или иной код. Они этого не знают.
если можно написать $result = 0
А вот здесь ты ерунду написал. В лучшем случае - NULL. Но я бы не стал вообще без нужды менять тип переменной.
Православно будет вызвать free(). Ну, или unset, на худой конец. А присваивать ноль - это как-то не очень.
либо вообще ни чего не писать, если переменная $result будет перезаписана в другом запросе?
лично я ничего и не пишу.
другое дело (поскольку цикл возвращает только последний результат, ха ха!), размер возвращённого значения может быть очень большим. и вот на этот редкий случай и пишут free(). можно написать один раз по окончании цикла.
Почему, во всех примерах, результат записывают в промежуточную переменную когда можно можно написать сразу
А вот здесь я с тобой не соглашусь.
"можно" не значит "нужно".
Старые программисты ещё помнят, что был когда-то такой язык - перл. На нём, как раз, можно было написать дофига всего в одну строчку.
Вот только проблема - написать-то можно, а прочесть-то как? пока программы только писали, перл был впереди всех, на своевом боевом коне.
А когда читать стали - ни одного смельчака не нашлось. Так перл и умер.
С тех пор умение написать дофига всего в одну строчку пересталось считаться джедайским.
А цениться стало умение написать код, который потом ещё и прочесть можно.

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

Надеюсь, понятно для непрограммиста изложил.
И ты это. Заходи ещё. Туговато тут с такими "нелепыми" вопросами.
 

topol

Новичок
Спасибо за ответы.

Фанат, благодарю за развернутый ответ.
Объяснили понятно. Но теперь я вообще не вижу смысла в этой функции.
Для чего разработчики создали отдельную функцию для уничтожения ресурса, если $result можно уничтожить, как обычную переменную, и ресурс освободится?

если можно написать $result = 0

А вот здесь ты ерунду написал. В лучшем случае - NULL. Но я бы не стал вообще без нужды менять тип переменной.
Православно будет вызвать free(). Ну, или unset, на худой конец. А присваивать ноль - это как-то не очень.
Я понимаю, не очень. Надо использовать то, что создано для этих целей. Просто, хотел обратить внимание, что можно уменьшить занимаемую память другим способом.

А по поводу смены типа данных, я читал, что php ругают за такую возможность. Только не вдавался в подробности.

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

Фанат

oncle terrible
Команда форума
Да нет, сможешь, конечно. При желании.
Тут проблема в том, что при возможности писать "самый ужасный код" его и пишут.

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

DotNET

Новичок
В соответствии с документацией mysqli_free_result освободит память, зарезервированную под ответ от подготавливаемых запросов.
В приведенном же коде:
PHP:
$a = $db->query('SELECT * FROM `t1` LIMIT 0, 1')->fetch_assoc();
$b = $db->query('SELECT * FROM `t1` LIMIT 0, 10')->fetch_all();
видим простые запросы.
Но даже и здесь сначала идет запись ответа сервера в память клиента в объект mysqli_result. В документации не говорится что fetch_assoc(), fetch_all() и прочие методы mysqli_result перемещают куда-то этот ответ или уничтожают его после себя автоматически. Следовательно, после команд, приведенных автором, результат запроса все еще в памяти клиента и ее нужно освободить спец. методом. Для этого и есть mysqli_result::free.

И еще, в приведенном коде:
PHP:
for($i=0;$i<3000000;$i++) {
    $a = $db->query('SELECT * FROM `t1` LIMIT ' . $i . ', 1')->fetch_assoc();    //    сразу возвращает результат в виде массива
    $result = $db->query('SELECT * FROM `t1` LIMIT ' . $i . ', 1');    //    $result будет перезаписана при следующей итерации
}
между $a и $result нет общего, в первую уже записана строка из таблицы `t1`, а во второй пока только mysqli-объект, из которого еще предстоит достать нужные строки из `t1`. Поэтому никаких промежуточных переменных - автор указал разные пути: первый дал всего лишь строку из таблицы, второй, более универсальный, потому что вернул объект с различными(!) методами манипуляции ответом без повторных запусков query().
 

Фанат

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

topol

Новичок
Но даже и здесь сначала идет запись ответа сервера в память клиента в объект mysqli_result. В документации не говорится что fetch_assoc(), fetch_all() и прочие методы mysqli_result перемещают куда-то этот ответ или уничтожают его после себя автоматически.
Вот, в первом сообщении я привел цитату и документации по PHP:
Освобождение ресурсов

Благодаря системе подсчета ссылок, введенной в PHP 4 Zend Engine, определение отсутствия ссылок на ресурс происходит автоматически, после чего он освобождается сборщиком мусора. Поэтому, очень редко требуется освобождать память вручную.
Я так понимаю, если нет ссылки на ресурс, ресурс будет уничтожен.
В приведенном мною примере:
PHP:
 $a = $db->query('SELECT * FROM `t1` LIMIT 0, 1')->fetch_assoc();
$b = $db->query('SELECT * FROM `t1` LIMIT 0, 10')->fetch_all();
, я сделал акцент на том, что переменные $a и $b содержат данные (массивы, не ссылки на ресурс). Следовательно, память, занимаемая результатом запроса, будет освобождена. В памяти же будут содержаться массивы $a и $b.

Следовательно, после команд, приведенных автором, результат запроса все еще в памяти клиента и ее нужно освободить спец. методом. Для этого и есть mysqli_result::free.
Почему он (результат запроса) в памяти, если ссылок на него нет? А mysqli_result::free мы не сможем применить, т.к. у нас нет объекта mysqli_result.

между $a и $result нет общего, в первую уже записана строка из таблицы `t1`, а во второй пока только mysqli-объект, из которого еще предстоит достать нужные строки из `t1`. Поэтому никаких промежуточных переменных - автор указал разные пути: первый дал всего лишь строку из таблицы, второй, более универсальный, потому что вернул объект с различными(!) методами манипуляции ответом без повторных запусков query().
Тут я и не утверждал обратного, по этому и назвал переменные не $a и $b, как в первом примере, a $a и $result. Можете обратить внимание на названия переменных в других моих примерах. $a, $b - переменные содержат массивы с данными, $result - объект mysqli_result
Суть кода состояла в том, чтобы проверить автоматическое освобождение памяти, при уничтожении ссылки на ресурс. Способ уничтожения ссылки указан в комментариях у соответствующих строк.
Извлекая данные поочередно из 3 000 000 строк БД, без последующего вызова mysqli_free_result, размер занимаемой памяти не изменялся. Следовательно, память, занимаемая результатом запроса, действительно, освобождается автоматически при уничтожении ссылки на ресурс (результат запроса).
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
бывают скрипты, которые работают долго, в которых исполняется множество запросов, и память надо освобождать.
посмотри mysqli_real_query(), mysqli_use_result() и mysqli_multi_query()

выполнение запроса не всегда означает получение данных в php, иногда надо освобождать буфер в mysql или в драйвере mysql
 
Сверху