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

발행: (2026년 5월 29일 AM 10:55 GMT+9)
4 분 소요
원문: Dev.to

Source: Dev.to

Laravel 대용량 데이터 처리

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

MethodMemorySQL QueriesSupports with()Safe to modify?
all()❌ High1
chunk()✅ LowMultiple⚠️ No
chunkById()✅ LowMultiple✅ Yes
cursor()✅ Lowest1
lazy()✅ LowMultiple

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

0 조회
Back to Blog

관련 글

더 보기 »