Laravel chunk() vs cursor() vs lazy() — 서버가 다운되지 않게 대용량 데이터 처리
Source: Dev.to

Introduction
Laravel에서 수천 개의 행을 처리하려다 메모리 오류나 서버 타임아웃이 발생한 적이 있다면—이 글이 바로 당신을 위한 것입니다. 대용량 CSV 내보내기로 인해 프로덕션에서 Apache 타임아웃 오류가 발생했을 때 힘들게 배운 내용입니다. 제가 발견한 내용을 정리했습니다.
The Problem
// ❌ This will crash on large tables
$users = User::all();
foreach ($users as $user) {
// process...
}
all()은 모든 행을 한 번에 메모리로 로드합니다. 100,000개 이상의 행이면 서버 메모리가 부족해집니다.
chunk() — Process in Batches
User::chunk(500, function ($users) {
foreach ($users as $user) {
// processes 500 rows at a time
}
});
- ✅ 메모리 사용량이 낮게 유지됩니다
- ✅ 백그라운드 작업에 적합합니다
- ⚠️
chunk()안에서 행을 수정/삭제하면 레코드가 건너뛰일 수 있습니다 - ⚠️ 여러 개의 SQL 쿼리를 실행합니다
사용 상황: 이메일을 배치로 보내거나 백그라운드 처리할 때.
chunkById() — Safer Version of chunk()
User::chunkById(500, function ($users) {
foreach ($users as $user) {
// safe even when updating rows
}
});
- ✅ 행을 업데이트/삭제해도 안전합니다
- ✅
chunk()보다 더 신뢰할 수 있습니다
사용 상황: 대량의 레코드를 업데이트하거나 삭제할 때.
cursor() — One Row at a Time
foreach (User::cursor() as $user) {
// processes one row at a time
}
- ✅ 가장 메모리 효율적입니다
- ✅ 단 하나의 SQL 쿼리만 사용합니다
- ❌ eager loading(
with())을 사용할 수 없습니다 - ❌ 전체 과정 동안 DB 연결이 열려 있습니다
사용 상황: 읽기 전용 처리, CSV 내보내기 등.
lazy() — Best of Both Worlds
foreach (User::lazy() as $user) {
// chunks behind the scenes, feels like cursor()
}
- ✅ 메모리 효율적입니다
- ✅
with()를 사용한 eager loading을 지원합니다 - ✅ 더 깔끔한 문법
User::with('orders')->lazy()->each(function ($user) {
// process
});
사용 상황: cursor()와 같은 반복 방식이 필요하면서 관계도 로드해야 할 때.
Quick Comparison Table
| Method | Memory | SQL Queries | Supports with() | Safe to modify? |
|---|---|---|---|---|
all() | ❌ High | 1 | ✅ | ✅ |
chunk() | ✅ Low | Multiple | ✅ | ⚠️ No |
chunkById() | ✅ Low | Multiple | ✅ | ✅ Yes |
cursor() | ✅ Lowest | 1 | ❌ | ✅ |
lazy() | ✅ Low | Multiple | ✅ | ✅ |
My Real‑World Example
CSV 내보내기에서 Apache 타임아웃 문제를 해결한 예시:
// ❌ Before — caused timeout
$users = User::all();
// ✅ After — works perfectly
foreach (User::cursor() as $user) {
fputcsv($handle, [
$user->name,
$user->email,
$user->created_at
]);
}
Summary
chunk()— 배치 작업, 이메일 전송chunkById()— 배치로 데이터를 수정할 때cursor()— 읽기 전용, CSV 내보내기, 가장 메모리 효율적lazy()—cursor()와 관계 로딩이 모두 필요할 때
더 깊이 파고들고 싶나요? 내 무료 Laravel 튜토리얼 사이트에서 전체 강의를 확인해 보세요:
https://php-laravel-tutorials.netlify.app/lesson-laravel-large-data