Speeding Up Laravel Tests with tmpfs (MySQL in RAM)
If your Laravel test suite is painfully slow and does a lot of database work (multi-tenancy, migrations, seeding), the bottleneck is almost…
When working with Laravel's Eloquent ORM, you may have noticed that you can access relationships with parentheses () and without. This small syntactical difference can have significant implications for your application's performance, especially when it comes to eager loading.
Before we jump into the parentheses issue, let's quickly recap how relationships are defined in Laravel:
class Property extends Model
{
public function propertyMedia()
{
return $this->hasMany(PropertyMedia::class);
}
}
This defines a one-to-many relationship between Property and PropertyMedia.
When you access a relationship without parentheses, like this:
$media = $property->propertyMedia;
You're treating the relationship as a property of the model. This is where eager loading shines. If you've eager loaded the relationship:
$property = Property::with('propertyMedia')->find($id);
Accessing $property->propertyMedia will use the preloaded data, not hitting the database again.
When you use parentheses:
$media = $property->propertyMedia();
You're calling the relationship method. This returns a query builder instance, allowing you to add constraints:
$photos = $property->propertyMedia()->where('type', 'photo')->get();
However, this approach bypasses eager loading, always resulting in a new query.
$property = Property::with('propertyMedia')->find($id);
$allMedia = $property->propertyMedia; // Uses eager loaded data
$property = Property::with('propertyMedia')->find($id);
$allMedia = $property->propertyMedia()->get(); // New query, ignores eager loading
The difference can be substantial:
In a loop or with multiple relationship accesses, using parentheses can lead to the dreaded N+1 query problem.
It's easy to accidentally use parentheses in views:
@foreach($property->propertyMedia() as $media) <!-- Bad: New query each time -->
@foreach($property->propertyMedia as $media) <!-- Good: Uses eager loaded data -->
Be careful with accessor methods:
public function getFirstPhotoAttribute()
{
return $this->propertyMedia()->where('type', 'photo')->first(); // Always queries
}
public function getFirstPhotoAttribute()
{
return $this->propertyMedia->where('type', 'photo')->first(); // Uses eager loaded data if available
}
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com