Community생산성 & 협업github.com

iserter/eloquent-best-practices

Laravel Eloquent ORM 사용 모범 사례: 쿼리 최적화, 관계 관리, N+1 쿼리와 같은 일반적인 함정 회피 방법을 제공합니다.

eloquent-best-practices란 무엇인가요?

이 스킬은 Laravel Eloquent ORM을 효과적으로 사용하기 위한 모범 사례를 제공합니다. 주요 내용으로는 쿼리 최적화 기법(eager loading, `withCount`, whereHas 등), 다양한 관계 유형(일대일, 일대다, 다대다, hasManyThrough, 다형성 관계) 및 피벗 테이블 작업, N+1 쿼리 방지, 그리고 `tap`, `when`, `whereHas` 같은 고급 기능을 활용한 효율적인 데이터 검색 방법을 다룹니다. 또한 고급 Eloquent/Collection 메서드와 캐싱, 모델 팩토리 사용, 서브쿼리, Blade 템플릿 최적화 등 모범 사례를 포함합니다. Laravel 개발자들이 깔끔하고 효율적인 Eloquent 쿼리를 작성하고 데이터베이스 성능을 최적화하는 데 도움을 줍니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/iserter/laravel-claude-agents/tree/main/skills/eloquent-best-practices

Installed? Explore more 생산성 & 협업 skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

eloquent-best-practices은(는) 무엇을 하나요?

Laravel Eloquent ORM 사용 모범 사례: 쿼리 최적화, 관계 관리, N+1 쿼리와 같은 일반적인 함정 회피 방법을 제공합니다.

참고: 이 문서는 Alexey Mezenin의 원본 laravel-best-practices 저장소에서 가져온 내용을 기반으로 Eloquent ORM 관련 모범 사례를 추출하고 정리한 것입니다.

목차

Eloquent ORM 모범 사례

쿼리 최적화

  • Eager Loading 사용 (N+1 문제 방지):

    • 관계 데이터를 필요로 할 때는 항상 with() 메서드를 사용하여 N+1 쿼리 문제를 방지하세요.
    • 예시:
      // 나쁜 예
      $users = User::all();
      foreach ($users as $user) {
          echo $user->profile->bio;
      }
      
      // 좋은 예
      $users = User::with('profile')->get();
      foreach ($users as $user) {
          echo $user->profile->bio;
      }
      
  • withCount 사용:

    • 관계 모델의 개수를 셀 때는 withCount() 메서드를 사용하여 추가 쿼리를 피하세요.
    • 예시:
      // 나쁜 예
      $posts = Post::all();
      foreach ($posts as $post) {
          echo $post->comments->count();
      }
      
      // 좋은 예
      $posts = Post::withCount('comments')->get();
      foreach ($posts as $post) {
          echo $post->comments_count;
      }
      
  • whereHas 사용:

    • 관계 조건에 따라 필터링할 때는 whereHas() 메서드를 사용하세요.
    • 예시:
      // 나쁜 예
      $users = User::all()->filter(function ($user) {
          return $user->posts->contains('status', 'published');
      });
      
      // 좋은 예
      $users = User::whereHas('posts', function ($query) {
          $query->where('status', 'published');
      })->get();
      
  • select 사용:

    • 필요하지 않은 열을 가져오지 않도록 select() 메서드를 사용하세요.
    • 예시:
      // 나쁜 예
      $users = User::all();
      
      // 좋은 예
      $users = User::select('id', 'name', 'email')->get();
      
  • chunk 또는 cursor 사용:

    • 대량의 데이터를 처리할 때는 chunk() 또는 cursor() 메서드를 사용하여 메모리 사용량을 줄이세요.
    • 예시:
      // 나쁜 예
      $users = User::all();
      foreach ($users as $user) {
          // 처리
      }
      
      // 좋은 예
      User::chunk(100, function ($users) {
          foreach ($users as $user) {
              // 처리
          }
      });
      
      // 또는 cursor 사용
      foreach (User::cursor() as $user) {
          // 처리
      }
      

관계 관리

  • 관계 정의시 명확한 이름 사용:

    • 관계 메서드 이름은 모델 이름을 기준으로 명확하게 지정하세요.
    • 예시:
      // 나쁜 예
      public function posts() { ... }
      public function author() { ... }
      
      // 좋은 예
      public function publishedPosts() { ... }
      public function postAuthor() { ... }
      
  • 다형성 관계 적절히 사용:

    • 여러 모델에서 공유되는 관계(예: 댓글)는 다형성 관계를 사용하세요.
    • 예시:
      // Comment 모델
      public function commentable() {
          return $this->morphTo();
      }
      
      // Post 모델
      public function comments() {
          return $this->morphMany(Comment::class, 'commentable');
      }
      
  • hasManyThrough 사용:

    • 중간 테이블을 통해 간접적인 관계를 정의할 때는 hasManyThrough를 사용하세요.
    • 예시:
      // Country -> User -> Post
      public function posts() {
          return $this->hasManyThrough(Post::class, User::class);
      }
      
  • 피벗 테이블 작업:

    • 다대다 관계에서 중간 테이블의 추가 열에 접근하려면 withPivot()을 사용하세요.
    • 예시:
      // Role 모델
      public function users() {
          return $this->belongsToMany(User::class)->withPivot('expires_at');
      }
      

함정 피하기

  • all() 남용 금지:

    • all() 메서드는 모든 레코드를 가져오므로 대규모 데이터셋에서는 피하세요. 대신 paginate() 또는 limit()을 사용하세요.
    • 예시:
      // 나쁜 예
      $users = User::all();
      
      // 좋은 예
      $users = User::paginate(20);
      
  • get() vs first():

    • 하나의 레코드만 필요할 때는 first()를 사용하고, 여러 레코드가 필요할 때는 get()을 사용하세요.
    • 예시:
      // 나쁜 예
      $user = User::where('email', $email)->get()->first();
      
      // 좋은 예
      $user = User::where('email', $email)->first();
      
  • pluck 사용으로 단일 열 값 가져오기:

    • 특정 열의 값만 필요할 때는 pluck()을 사용하세요.
    • 예시:
      // 나쁜 예
      $userEmails = User::all()->pluck('email');
      
      // 좋은 예
      $userEmails = User::pluck('email');
      
  • tap 사용 (선택적):

    • 쿼리 빌더 체이닝에서 중간 값을 처리할 때 tap()을 사용할 수 있습니다.
    • 예시:
      // tap 사용 예
      $user = tap(User::where('email', $email)->first(), function ($user) {
          $user->update(['last_login_at' => now()]);
      });
      
  • when 사용:

    • 조건부 쿼리를 작성할 때 when() 메서드를 사용하세요.
    • 예시:
      // 나쁜 예
      $query = User::query();
      if ($request->has('role')) {
          $query->where('role', $request->role);
      }
      $users = $query->get();
      
      // 좋은 예
      $users = User::when($request->has('role'), function ($query) use ($request) {
          $query->where('role', $request->role);
      })->get();
      

참고 자료

관련 스킬