Laravel Eloquent 팁 & 트릭: 모든 프로 개발자가 알아야 할 것
Source: Dev.to
Laravel Eloquent는 PHP 생태계에서 가장 강력하고 표현력이 뛰어난 ORM 시스템 중 하나입니다. 하지만 대부분의 개발자는 Eloquent가 실제로 할 수 있는 일의 표면만을 살펴봅니다. 이 글에서는 프로 개발자들이 더 깔끔하고, 빠르며, 확장 가능한 애플리케이션을 작성하기 위해 사용하는 고급 Laravel Eloquent 팁과 모범 사례를 다룹니다.
N+1 쿼리 문제 피하기
// Bad Practice
$posts = Post::all();
foreach ($posts as $post) {
echo $post->user->name;
}
위 코드는 각 포스트의 사용자를 가져오기 위해 별도의 쿼리를 실행합니다.
// Best Practice
$posts = Post::with('user')->get();
Eager loading을 사용하면 데이터베이스 쿼리 수를 크게 줄이고 성능을 향상시킬 수 있습니다.
필요한 컬럼만 선택하기
// Bad Practice
User::all();
불필요한 컬럼을 가져오면 메모리 사용량이 증가하고 쿼리 속도가 느려집니다.
// Best Practice
User::select('id', 'name', 'email')->get();
실제로 필요한 데이터만 가져오도록 항상 선택하세요.
Chunking을 이용한 대용량 데이터 처리
// Bad Practice (may exhaust memory)
User::all();
// Best Practice
User::chunk(100, function ($users) {
foreach ($users as $user) {
// process user
}
});
Chunking은 메모리 사용량을 낮게 유지해 주며 백그라운드 작업이나 크론 작업에 이상적입니다.
복잡한 관계 다루기
Laravel은 hasOneThrough, hasManyThrough, 그리고 다형 관계와 같은 고급 관계 타입을 지원합니다.
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
이러한 관계는 데이터베이스 설계를 깔끔하고 확장 가능하게 유지하는 데 도움을 줍니다.
재사용성을 위한 Query Scope 사용
// Usage
User::active()->admin()->get();
public function scopeActive($query)
{
return $query->where('status', 'active');
}
Scope를 사용하면 쿼리를 읽기 쉽고 재사용 가능하게 만들 수 있습니다.
Mass Assignment 방지
// Bad Practice
User::create($request->all());
// Best Practice
protected $fillable = ['name', 'email'];
// or
protected $guarded = ['is_admin'];
$fillable 또는 $guarded를 정의하면 무단 데이터 수정으로부터 보호할 수 있습니다.
효율적인 존재 여부 확인
// Bad Practice
User::where('email', $email)->count();
// Best Practice
User::where('email', $email)->exists();
exists()는 매치가 발견되는 즉시 쿼리를 중단하므로 더 빠릅니다.
관계를 로드하지 않고 카운트하기
// Bad Practice
$post->comments->count();
// Best Practice
Post::withCount('comments')->get();
withCount는 전체 관계를 로드하지 않고도 개수를 가져올 수 있습니다.
대량 업데이트 수행하기
// Bad Practice
$user = User::find($id);
$user->status = 'active';
$user->save();
// Best Practice
User::where('id', $id)->update(['status' => 'active']);
이렇게 하면 데이터베이스 쿼리 수를 줄일 수 있습니다.
firstOrCreate로 레이스 컨디션 방지
User::firstOrCreate(
['email' => $email],
['name' => $name]
);
이 메서드들은 로직을 단순화하고 레이스 컨디션을 방지합니다.
속성 캐스팅
protected $casts = [
'is_active' => 'boolean',
'settings' => 'array',
'email_verified_at' => 'datetime',
];
캐스팅을 통해 애플리케이션 전반에 걸쳐 일관된 데이터 타입을 보장합니다.
민감한 속성 숨기기
protected $hidden = [
'password',
'remember_token',
];
이 필드들을 숨기는 것은 API 보안에 필수적입니다.
중요한 작업에 데이터베이스 트랜잭션 사용
DB::transaction(function () {
Order::create([...]);
Payment::create([...]);
});
트랜잭션을 사용하면 부분적인 데이터 손상을 방지할 수 있습니다.
쿼리 모니터링으로 병목 현상 파악
DB::listen(function ($query) {
logger($query->sql);
});
정기적인 쿼리 모니터링은 성능 문제를 조기에 식별하는 데 도움이 됩니다.