#php #laravel #memory #pdo
#php #laravel #память #pdo
Вопрос:
Я нашел отличный пример, написанный на php pdo, который помогает перебирать огромное количество данных, фактически не выделяя память для всего набора результатов:
$sql = 'SELECT * from playlists limit 50000';
$statement = $pdo->prepare($sql);
$statement->execute();
while (($result = $statement->fetch(PDO::FETCH_ASSOC)) !== false) {
//do something
}
Я провел исследование, и этот подход использует 18mb
объем памяти.
Если я получу все результаты, подобные этому, $results = $statement->fetchAll(PDO::FETCH_ASSOC);
использование памяти увеличится до 35mb
.
Использование illuminate/database
компонента laravel и очень похожего подхода DB::table('playlists')->limit(50000)->get();
также использует 35mb
объем памяти.
- Как я могу достичь первого подхода, используя Laravel eloquent или фасад DB?
- Не могли бы вы предложить несколько статей о том, как развивается эта разница в использовании памяти?
Спасибо
Комментарии:
1. Вы сравниваете подобное с подобным? Фреймворк Laravel имеет свои собственные накладные расходы. Проверьте использование памяти Laravel без выполнения запроса и проверьте, насколько увеличилось использование памяти при выполнении запроса. Сравните это с использованием памяти без Laravel до и после выполнения запроса
Ответ №1:
Когда вы выполняете SQL-запрос с помощью php (либо функций mysql, либо PDO), все данные, возвращенные из запроса, загружаются в память в виде «набора результатов».
Чтобы использовать данные в «наборе результатов», вы должны извлекать их из обычных php-массивов / объектов.
PDOStatement::fetch — извлекает одну строку из результирующего набора в память.
PDOStatement::fetchAll — извлекает все строки из результирующего набора в память, тем самым удваивая использование памяти.
Eloquent обладает способностью разбивать на части результирующие наборы. Это эквивалентно выполнению «X-кратной выборки» в PDO.
Однако, если вы работаете с очень большими наборами результатов, рассмотрите возможность использования ограничений SQL.
Комментарии:
1. Допустим, я увеличил объем памяти на 100. Таким образом, при выполнении каждого фрагмента будет выделяться память для 100 строк или только для одной?
2. @EvaldasButkus Каждое выполнение фрагмента загружает в память 100 строк одновременно. Во втором фрагменте первый фрагмент переопределяется вторым фрагментом. Таким образом, теоретически максимальное использование памяти должно составлять результирующий набор размер блока.
Ответ №2:
Подход Laravel к обработке больших наборов данных, подобных этому, заключается в использовании разбиения на фрагменты.
DB::table('playlists')->chunk(1000, function($playlists) use($count) {
foreach($playlists as $playlist) {
// do something with this playlist
}
});
Это гарантирует, что в оперативную память одновременно загружается не более размера блока (в моем примере 1000 строк). 1 кб является произвольным; вы могли бы разделить 1, 100, 253 и т.д.
Комментарии:
1. Если вы хотите ограничить ее максимум 50 тысячами строк, вам нужно будет выполнить небольшую логику, чтобы отслеживать итерации в цикле.