Експорт даних в Excel і CSV: продуктивність та асинхронність
Уявіть: клієнт формує звіт по продажах за рік — 50 тисяч рядків. Синхронний експорт вивантажує всі дані в пам'ять, через 30 секунд користувач бачить таймаут, а сервер споживає 500 MB RAM. Типова картина для проектів, де генерацію звітів реалізували «на швидку руку». Ми вирішуємо цю проблему асинхронним експортом із потоковим записом, скорочуючи час генерації до 80% і знижуючи навантаження на сервер у 10 разів. Нижче розповім, як це працює та які технології використовуємо.
Проблеми, з якими стикаються при генерації звітів
Витік пам'яті при великих вибірках. Стандартний підхід — SELECT * FROM orders — вивантажує всі рядки в PHP-масив. При 100 000 записів це 600 MB пам'яті. Використовуємо chunk-ітератори: Order::lazy(500) або Order::chunk(1000), щоб обробляти дані порціями по 500–1000 рядків. Споживання пам'яті не перевищує 50 MB.
Відсутність стилів і формул. CSV-експорт не підходить для фінансових звітів: потрібні формули SUM, закріплені шапки, умовне форматування. Реалізуємо кастомні стилі через PhpSpreadsheet або ExcelJS: шрифти, кольори, межі, автофільтри, зведені таблиці.
Довге очікування користувача. При синхронному експорті користувач чекає завершення запиту. Для 200 000 рядків — до 2 хвилин. Асинхронна генерація через черги (Laravel Horizon, Bull) надсилає файл на email або в особистий кабінет, не блокуючи інтерфейс. Асинхронний експорт у 3 рази швидше синхронного.
Як асинхронний експорт вирішує проблему продуктивності?
Ключовий патерн — FromQuery з WithChunkReading в Laravel Excel. Приклад:
class LargeExport implements FromQuery, WithChunkReading
{
public function query(): Builder
{
return Order::with('items', 'user')->orderBy('id');
}
public function chunkSize(): int
{
return 1000;
}
}
// Controller
public function exportLarge(Request $request): JsonResponse
{
$filename = 'orders-' . now()->format('Y-m-d-H-i') . '.xlsx';
Excel::queue(new LargeExport, $filename, 's3')
->chain([new NotifyUserOfCompletedExport($request->user(), $filename)]);
return response()->json(['message' => 'Експорт запущено, ви отримаєте сповіщення по готовності']);
}
Тут Excel::queue відправляє задачу в чергу, яка виконується у фоні. Після завершення ланцюжка надсилається сповіщення. Споживання пам'яті — 50 MB, навіть для мільйона записів.
Порівняння підходів: синхронний vs асинхронний експорт
| Параметр | Синхронний | Асинхронний (черга) |
|---|---|---|
| Макс. рядків | до 10 000 | мільйони |
| Споживання RAM | 500+ MB | 50 MB |
| Відгук користувача | 30 сек | миттєвий |
| Відмовостійкість | немає | так (повторні спроби) |
Асинхронний підхід кращий для корпоративних звітів — він обробляє мільйони рядків, не блокуючи інтерфейс, і автоматично повторює задачу при збоях.
Детальніше про технології
Для роботи з великими даними використовуємо потокову архітектуру (streaming), що дозволяє записувати рядки безпосередньо у файл, оминаючи пам'ять. Це критично для обсягів понад 500 000 рядків.Чому варто обрати Laravel Excel для експорту?
Laravel Excel — обгортка над PhpSpreadsheet, що надає контракти FromCollection, FromQuery, WithHeadings. Легко інтегрується з чергами та хмарними сховищами. Альтернатива — ExcelJS для Node.js. Порівняння:
| Параметр | Laravel Excel (PHP) | ExcelJS (Node.js) | CSV (універсальний) |
|---|---|---|---|
| Стилізація | Так (через макроси) | Так (вбудована) | Немає |
| Формули | Так | Так | Немає |
| Потоковий запис | Через FromQuery |
Так | Так |
| Черги | Вбудовано | Ручна реалізація | Немає |
| Підтримка .xlsx | Так | Так | Немає |
Якщо проект на PHP — обираємо Laravel Excel, на Node.js — ExcelJS. CSV-експорт використовуємо лише для простих вивантажень без форматування.
Процес роботи над інтеграцією генерації звітів
- Аналіз — збираємо вимоги: поля, фільтри, формат, необхідність фонової генерації.
- Проектування — обираємо стек (Laravel/Node.js), проектуємо структуру файлу (аркуші, групування, формули).
- Реалізація — пишемо код експорту, налаштовуємо обробку помилок, логування.
- Тестування — перевіряємо на реальних даних (10% обсягу), коригуємо стилі.
- Деплой — налаштовуємо черги, крон-завдання (якщо потрібна періодична генерація), документуємо.
Строки орієнтовно
- Базовий експорт (один аркуш, прості стилі): 2–3 дні. Вартість від $1000.
- Асинхронний експорт з великими даними: 3–4 дні.
- Складний багатоаркушевий звіт з формулами та зведеними таблицями: до тижня.
Точні строки залежать від кількості аркушів та складності форматування.
Що входить в роботу
- Вихідний код генератора звітів (PHP або Node.js).
- Конфігурація черг та сховища (S3, локальний диск).
- Документація з використання (кастомізація полів, додавання аркушів).
- Інтеграція з вашою аутентифікацією та правами доступу.
- Навчання співробітників (1–2 години).
- Гарантія технічної підтримки протягом 30 днів після здачі. Сертифіковані інженери з 5+ років досвіду.
Типові помилки при самостійній реалізації
- Завантаження всіх даних в пам'ять — використовуйте chunk.
- Відсутність черг — користувач чекає генерації.
- Ігнорування стилів — звіт нечитабельний.
- Одна таблиця на всі дані — розбивайте на аркуші.
Зв'яжіться з нами для аналізу вашого проекту — ми оцінимо обсяг даних, поточний стек і запропонуємо оптимальне рішення. Досвід наших інженерів — понад 5 років на ринку, більше 50 успішних проектів з інтеграції генерації звітів. Замовте реалізацію генерації звітів вже сьогодні та отримайте надійний інструмент для аналітики.







