Какими способами организовать порционную обработку данных в PHP? кратко

Лекция



Привет, Вы узнаете о том , что такое порционная обработка данных, Разберем основные их виды и особенности использования. Еще будет много подробных примеров и описаний. Для того чтобы лучше понимать что такое порционная обработка данных , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend) .

В PHP можно организовать обработку данных порциями разными способами, в зависимости от того, с чем именно мы работаем: с базой данных, файлами или массивами.

В PHP порционная обработка данных (batch / chunk processing) обычно нужна, когда данных много и нельзя грузить все в память или обрабатывать за один запрос.

Основные методы:

  • SQL-запрос с LIMIT и OFFSET
  • Чтение файла построчно (fgets(), SplFileObject)
  • Итерация по массиву с array_chunk()
  • Использование генераторов (yield)

Какими способами организовать порционную обработку данных в PHP?

рассмотрим эти и другие методы более подробнее

Постраничная выборка в SQL (LIMIT + OFFSET)

При работе с базой данных мы можем загружать данные порциями с помощью LIMIT и OFFSET

$limit = 10; // Количество записей на страницу

$offset = 0; // Смещение (номер страницы * $limit)

$sql = "SELECT * FROM users ORDER BY id LIMIT $limit OFFSET $offset";

$result = $pdo->query($sql)->fetchAll();

Альтернативный вариант – постраничная выборка без OFFSET

$last_id = 0;

$sql = "SELECT * FROM users WHERE id > $last_id ORDER BY id LIMIT $limit";

Плюсы

  • Просто

  • Подходит для небольших таблиц

Минусы

  • OFFSET медленный на больших таблицах

  • Проблемы при изменении данных во время обработки

Используй только до ~100k записей

Порционная выборка по ID (рекомендуемый способ)

Идея: двигаться по первичному ключу.

$limit = 100; 
$lastId = 0; 
do 
{
 $rows = $db
          ->query( "SELECT * FROM users WHERE id > $lastId ORDER BY id LIMIT $limit" )
          ->fetchAll(); 
  foreach ($rows as $row) {
    process($row); 
    $lastId = $row['id']; 
   } 
}  while (!empty($rows)); 

Плюсы

  • Очень быстро

  • Не ломается при больших объемах

  • Стабильно при параллельных изменениях

Минусы

  • Нужен монотонный ключ (id, created_at)

Лучший вариант для БД

Чтение файла порциями (fgets(), SplFileObject, JsonMachine) (CSV, TXT, JSON)

При работе с большими файлами можно читать их построчно, а не загружать в память целиком.fgets() – чтение построчно

$handle = fopen("large_file.txt", "r");

while (($line = fgets($handle)) !== false) {

echo $line;

}

fclose($handle);

SplFileObject – более удобный способ

$file = new SplFileObject("large_file.txt");

while (!$file->eof()) {

echo $file->fgets();

}

JSON (большие файлы)

  • Использовать JsonMachine

  • Или потоковое чтение

foreach (JsonMachine\Items::fromFile('big.json') as $item) { 
    process($item); 
}

Разделение массива на порции (`array_chunk()`)

Если у нас массив данных, можно разбить его на части

$data = range(1, 100);

$chunks = array_chunk($data, 10);

foreach ($chunks as $chunk) {

print_r($chunk); // Выведет массивы по 10 элементов

}

Генераторы ( yield ) – ленивый способ

Генераторы позволяют возвращать элементы по одному, не загружая все в память сразу.

Идея: обрабатывать данные по одной записи, но читать пачками.

function getData() {

for ($i = 1; $i <= 100; $i++) {

yield $i; // Возвращает по одному значению

}

}

foreach (getData() as $num) {

echo $num . "\n";

}

пример для выборки данных из бд

function getUsers(PDO $db, int $chunk = 100): Generator {
    $lastId = 0;

    while (true) {
        $stmt = $db->prepare(
            "SELECT * FROM users WHERE id > :id ORDER BY id LIMIT :limit"
        );
        $stmt->bindValue(':id', $lastId, PDO::PARAM_INT);
        $stmt->bindValue(':limit', $chunk, PDO::PARAM_INT);
        $stmt->execute();

        $rows = $stmt->fetchAll();
        if (!$rows) {
            break;
        }

        foreach ($rows as $row) {
            $lastId = $row['id'];
            yield $row;
        }
    }
}

Использование:

foreach (getUsers($db) as $user) { 
   process($user); 
}

Плюсы

  • Минимум памяти

  • Чистый код

Генераторы (yield) в PHP — штука мощная, но не серебряная пуля. Об этом говорит сайт https://intellect.icu . В контексте порционной обработки данных / ETL / batch-скриптов у них есть вполне реальные минусы.

Основные минусы генераторов (yield)

1 Нельзя «перемотать назад»

Генератор — одноразовый поток.

$gen = getUsers(); foreach ($gen as $u) {} foreach ($gen as $u) {} //   не сработает 

Если нужна повторная обработка — генератор надо создавать заново.

2 Сложно отлаживать

  • нельзя просто var_dump($gen)

  • нельзя посмотреть «все данные»

  • стек вызовов хуже читается

При ошибках внутри yield дебаг неприятнее, чем с массивами.

3 Ошибки «вылезают» поздно

$gen = getUsers(); // OK 
 // ... 
foreach ($gen as $row) { 
  // ❌ ошибка здесь, а не при создании 
} 

Исключение возникает в момент итерации, а не инициализации — это иногда ломает логику обработки ошибок.

4 Не подходит, если нужны все данные сразу

Генераторы плохо подходят для:

  • сортировки

  • поиска по всему набору

  • повторного прохода

  • подсчета итогов без промежуточного состояния

$count = count($gen); //  Нужно копить данные — и смысл yield пропадает.

5 Сложно комбинировать с транзакциями

 $db->beginTransaction(); 
 foreach (getUsers($db) as $row) {
   process($row); // долгий процесс 
 }
 $db->commit(); //   долго открытая транзакция 

Транзакции могут висеть минутами, что плохо для БД.

6 Накладные расходы на каждый yield

  • каждый yield — переключение контекста

  • медленнее, чем простой while + массив, если данных мало

Для малых объемов генераторы часто медленнее, а не быстрее.

7 Сложнее делать retry и откаты

Если:

  • процесс упал на середине

  • сервер перезапустился

генератор не знает, где он был

Нужно вручную:

  • хранить lastId

  • писать чекпоинты

  • логировать прогресс

8 Не все PHP-разработчики умеют с ними работать

  • сложнее читать код

  • больше ошибок при поддержке

  • «магия» для джунов

В командной разработке это реальный минус.

Когда генераторы — плохой выбор

Нужна повторная обработка данных
Нужна сортировка / агрегация всего набора
Есть транзакции на большие блоки
Нужны гарантии восстановления после падения
Код поддерживает большая команда

Когда генераторы — отличный выбор

Огромные данные
Минимум памяти
Последовательная обработка
Read-only сценарии
ETL без строгих rollback’ов

yield — это оптимизация памяти, а не архитектура обработки

Он отлично решает одну задачу (memory),
но не решает:

  • надежность

  • повторы

  • контроль выполнения

Очереди задач (RabbitMQ, Redis, Beanstalkd)

Идея: данные → очередь → воркеры

queue()->push(['user_id' => 123]); 

Воркер:

while ($job = queue()->pop()) { process($job); } 

Плюсы

  • Масштабируемо

  • Можно распараллелить

  • Отказоустойчиво

Для тяжелых и долгих задач — лучший выбор

Общие минусы очередей (в целом)

Независимо от реализации:

  • Сложность архитектуры
    Уже не «один PHP-скрипт», а:

    • брокер

    • продюсеры

    • воркеры

    • мониторинг

  • Сложнее отлаживать
    Ошибка может быть:

    • в очереди

    • в воркере

    • в повторной доставке

  • Не моментальный результат
    Это асинхронная модель — пользователь не ждет выполнения

  • Нужно следить за падениями воркеров
    Без supervisor / systemd все ломается

CRON + контроль состояния

Идея: обрабатывать частями по времени.

// берем 100 необработанных SELECT * FROM tasks WHERE processed = 0 LIMIT 100; 

После обработки:

UPDATE tasks SET processed = 1 WHERE id = ?; 

Подходит для:

  • Импорта

  • Синхронизаций

  • Регулярных джоб

CLI-скрипты + pcntl (параллельно)

php process.php --chunk=1000 

Можно форкать:

pcntl_fork(); 

Используется в high-load и ETL (E — Extract (извлечение) T — Transform (преобразование) L — Load (загрузка))

Как выбрать?

Сценарий Лучший вариант
Малый объем LIMIT + OFFSET
Большая БД WHERE id > lastId
Мало памяти Generators
Долгие задачи Очереди
Регулярно CRON
Максимальная скорость CLI + очередь

Исследование, описанное в статье про порционная обработка данных, подчеркивает ее значимость в современном мире. Надеюсь, что теперь ты понял что такое порционная обработка данных и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)

Из статьи мы узнали кратко, но содержательно про порционная обработка данных
создано: 2026-02-01
обновлено: 2026-03-10
22



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:
Пожаловаться

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей

Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)

Термины: Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)