I want to apply a where
condition to relation. Here's what I do:
Replay::whereHas('players', function ($query) { $query->where('battletag_name', 'test'); })->limit(100);
It generates the following query:
select * from `replays` where exists ( select * from `players` where `replays`.`id` = `players`.`replay_id` and `battletag_name` = 'test') order by `id` asc limit 100;
Which executes in 70 seconds. If I manually rewrite query like this:
select * from `replays` where id in ( select replay_id from `players` where `battletag_name` = 'test') order by `id` asc limit 100;
It executes in 0.4 seconds. Why where exists
is the default behavior if it's so slow? Is there a way to generate the correct where in
query with query builder or do I need to inject raw SQL? Maybe I'm doing something wrong altogether?
replays
table has 4M rows, players
has 40M rows, all relevant columns are indexed, dataset doesn't fit into MySQL server memory.
Update: found that the correct query can be generated as:
Replay::whereIn('id', function ($query) { $query->select('replay_id')->from('players')->where('battletag_name', 'test'); })->limit(100);
Still have a question why exists
performs so poorly and why it is the default behavior
whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.
The reason make query so slow is because of Eloquent creating object for each parameter before binding. The suggested solution was use Query Builder for such a task.
Laravel's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application and works perfectly with all of Laravel's supported database systems.
Check if not null: whereNotNullSELECT * FROM users WHERE last_name IS NOT NULL; The equivalent to the IS NOT NULL condition in Laravel Eloquent is the whereNotNull method, which allows you to verify if a specific column's value is not NULL .
Try this:
Replay::hasByNonDependentSubquery('players', function ($query) { $query->where('battletag_name', 'test'); })->limit(100);
That's all. Happy Eloquent Life!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With