Оптимизация обработки больших массивов данных с Lazy Collection
Понимание Lazy Collection
Lazy Collection, появившиеся в Laravel 6.0, позволяют работать с очень большими наборами данных, не загружая в память сразу весь набор. Они работают, загружая элементы по мере необходимости, что делает их идеальными для обработки больших файлов или работы с большими наборами результатов базы данных.
Базовое применение
Простой пример создания и использования ленивой коллекции (Lazy Collection):
use Illuminate\Support\LazyCollection;
LazyCollection::make(function () {
$handle = fopen('large-file.csv', 'r');
while (($line = fgets($handle)) !== false) {
yield str_getcsv($line);
}
})->each(function ($row) {
// Обработка каждого ряда
});
Этот код считывает большой CSV-файл построчно, не загружая его целиком в память.
Работа с результатами запроса к базе данных
Lazy Collection особенно удобны при работе с большими наборами результатов из баз данных:
User::cursor()->each(function ($user) {
// Обработка каждого пользователя
});
Метод cursor()
возвращает Lazy Collection, что позволяет эффективно перебирать большое количество записей базы данных.
Разбивка результатов
Для ещё более эффективной обработки можно комбинировать Lazy Collections с разбивкой на части:
LazyCollection::make(function () {
for ($i = 0; $i < 1000000; $i++) {
yield $i;
}
})
->chunk(1000)
->each(function ($chunk) {
// Обработка фрагмента из 1000 элементов
DB::table('numbers')->insert($chunk->all());
});
Такой подход полезен, когда необходимо выполнять пакетные операции, например, вставку данных в базу данных.
Преобразование данных
Lazy Collection поддерживает множество тех же методов, что и обычные Коллекции Laravel:
LazyCollection::make(function () {
yield from ['apple', 'banana', 'cherry'];
})
->map(function ($item) {
return strtoupper($item);
})
->each(function ($item) {
echo $item . "\n";
});
Реальный пример: Обработка большого log-файла
Более сложный пример, в котором обрабатывается большой log-файл:
LazyCollection::make(function () {
$handle = fopen('large-log-file.log', 'r');
while (($line = fgets($handle)) !== false) {
yield $line;
}
})
->map(function ($line) {
return json_decode($line, true);
})
->filter(function ($log) {
return $log['level'] === 'error';
})
->chunk(100)
->each(function ($chunk) {
ErrorLog::insert($chunk->all());
});
Этот скрипт построчно считывает большой log-файл, декодирует каждую строку из JSON, фильтрует логи на предмет ошибок и вставляет их в базу данных фрагментами по 100 элементов.
Производительность
Хотя Lazy Collection эффективны с точки зрения памяти, они могут быть медленнее для небольших наборов данных из-за накладных расходов на генерацию элементов по требованию. Для малых и средних наборов данных лучше использовать обычные коллекции.
Lazy Collection в Laravel — мощный инструмент для эффективной работы с большими массивами данных. Загружая данные по требованию, они позволяют обрабатывать огромные объёмы информации, не сталкиваясь с нехваткой памяти. Если вы работаете с большими файлами, выполняете объёмные запросы к базе данных или любой другой сценарий, связанный с большими данными, Lazy Collection могут значительно повысить производительность и масштабируемость приложения.