Я хочу применить where
условие отношения. Вот что я делаю:
Replay::whereHas('players', function ($query) {
$query->where('battletag_name', 'test');
})->limit(100);
Он генерирует следующий запрос:
select * from `replays`
where exists (
select * from `players`
where `replays`.`id` = `players`.`replay_id`
and `battletag_name` = 'test')
order by `id` asc
limit 100;
Который выполняется за 70 секунд. Если я вручную переписать запрос, как это:
select * from `replays`
where id in (
select replay_id from `players`
where `battletag_name` = 'test')
order by `id` asc
limit 100;
Выполняется за 0,4 секунды. Зачем where exists
такое поведение по умолчанию, если оно такое медленное? Есть ли способ сгенерировать правильный where in
запрос с помощью построителя запросов или мне нужно ввести сырой SQL? Может я вообще что-то не так делаю?
replays
таблица имеет 4M строк, players
имеет 40M строк, все соответствующие столбцы проиндексированы, набор данных не помещается в память сервера MySQL.
Обновить: обнаружил, что правильный запрос может быть сгенерирован как:
Replay::whereIn('id', function ($query) {
$query->select('replay_id')->from('players')->where('battletag_name', 'test');
})->limit(100);
Еще есть вопрос почему exists
работает так плохо и почему это поведение по умолчанию
Я думаю, что производительность не зависит от того, где есть, только зависит от того, сколько записей вы выбрали
Плюс попробуйте оптимизировать ваш сервер MySQL
https://dev.mysql.com/doc/refman/5.7/en/optimize-overview.html
а также оптимизировать ваш php сервер
и если у вас есть быстрый запрос, почему бы вам не использовать необработанный объект запроса от личинок
$replay = DB::select('select * from replays where id in (
select replay_id from players where battletag_name = ?)
order by id asc limit 100', ['test']
);
Других решений пока нет …